개발환경
springboot
jdk1.8
mysql
mybatis
들어가기
spring 개발을 할때, 난 일반적으로 mybatis를 사용했다.
음 빨리 JPA도 공부를 해야 할거 같다.
일반적으로 mybatis를 사용할 경우 ${param1}, #{param2} 이렇게 두가지 방식으로 파라미터를 받을 수 있다.
나는 보통 #{param2} 를 사용해서, 파라미터를 받는다.
1 | SELECT * |
#{} 는 내부적으로 PreparedStatement를 사용하기 때문에 SQLInjection 공격에 안전하기 때문이다.
참고로 PreparedStatement는 값을 바인딩 하는 시점에서 전달된 값에 대한 특수문자, 쿼리등을 필터링하여 SQLinjection을 막는다.
이렇게 mybatis를 사용할때 보통 #{}를 사용하면 평화롭고, 안전한 코딩을 할 수 있다.
하지만 간혹 ${}를 사용하고 싶을 때가 있다.
바로 쿼리의 파라미터로 컬럼명을 화면에서 받고 싶은 경우인데,
보통 select 쿼리에 호출시 정렬을 하고 싶을 때 이다.
1 | SELECT |
위처럼 동적으로 파라미터를 외부에 주입 받기 위해서는 #{}가 아닌 ${}를 사용 해야 한다.
${}는 입력받은 파라미터를 쿼리에 직접 치환해주기 때문이다.
하지만 여기에는 SQLInjection에 대한 위험이 존재한다.
어떻게 하면 ${}를 사용하면서, SQL Injection을 방어 할 수 있을까?
스프링 필터를 사용해야하나? AOP를 사용해야 하나?
고민하다가 인터넷에서 괜찮은 라이브리러를 찾았다.
어노테이션으로 SQL Injection 방어
https://github.com/rkpunjal/sql-injection-safe/
sql-injection-safe 라는 라이브러리이다.
아이디어는 어노테이션으로 VO의 필드에 SqlInjection을 방어하는 방법이다.
아래로 가보면 간단하게 테스트 할수 있는 예제 샘플도 있다.
https://github.com/rkpunjal/sql-safe-annotation-example
일단 동적으로 sql의 컬럼을 받을 VO를 만들어보자.
1 | class GridDto{ |
위처럼 대충 DTO를 만들었다.
자 이제 라이브러리를 추가하자. pom.xml 아래처럼 추가하자.
1 | <dependency> |
라이브러리가 추가 되었다면, Sql Injection 위험이 있는 DTO의 필드에 @SQLInjectionSafe 어노테이션을 추가해준다.
1 | class GridDto{ |
그리고 해당 DTO를 받은 컨트롤러에서 @valid를 적용해주면 된다.
굉장히 간단하게 스프링 컨트롤러에서 전달되는 파라미터에 어노테이션으로 SQL Injection을 방어 할 수 있다.
1 | "/queryGrid", produces=APPLICATION_JSON_UTF_8) (value = |
@Valid 가 동작하면서 @SQLInjectionSafe 동작한다.
만약 sortColumn 멤버변수에 SQL Injection의 위험이 되는 문구가 있는 경우 BindException 이 발생하게된다.
1 | .class) (BindException |
https://github.com/rkpunjal/sql-safe-annotation-example
위 예제 샘플을 받아서 구동해보면 아래처럼 @SQLInjectionSafe 내용을 확인 할 수 있다.
SQLInjection을 정규식으로 잡아내는 것을 확인 할 수 있다.
뭔가 부족하다면 커스텀 하면 될거 같다.