웹 개발

spring boot에서 mybatis ${} 사용시 sql injection 방어하기

노루아부지 2020. 11. 21. 22:56

mybatiss를 사용할 경우 ${param}, #{param}과 같이 # 또는 $으로 parameter를 받을 수 있는데, 보통 아래와 같이 #을 사용해서 받는 것을 권장합니다. 그 이유는, #{}이 SQL Injection 공격에 안전하기 때문인데요

 

SELECT *
FROM TB_USER
WHERE USER_ID = #{userId}

 

#이 SQL Injection에 안전한 이유는,  #이 내부적으로 PreparedStatement를 사용하기 때문입니다. PreparedStatement는 값을 binding 하는 시점에 전달된 값에 대한 특수 문자, 쿼리 등을 필터링하여 SQL Injection을 막습니다.

 

하지만 ${}를 부득이하게 사용해야 할 경우가 있습니다. 제가 다니는 회사를 예로 들면, 고객사가 스키마명을 변경해 달라고 하는 경우가 있는데 이 경우 모든 쿼리를 수정할 수 없기 때문에 어쩔 수 없이 $를 사용합니다.

 

문제는, $을 사용하면 mybatis에서 SQL Injection을 막아 줄 수 없다는 것인데요.

이런 경우 java에서 SQL Injection 방어 코딩을 해야 하는데, 너무 번거로워 라이브러리를 찾아봤습니다.

 

바로 github.com/rkpunjal/sql-injection-safe/ 라이브러리입니다.

이 라이브러리는 VO의 필드에 Annotaion을 사용하여 SQL Injection을 방어하는 방법입니다.

 

사용방법은 간단합니다.

 

먼저, pom.xml에 아래와 같이 dependency를 추가합니다.

<dependency>
  <groupId>com.github.rkpunjal.sqlsafe</groupId>
  <artifactId>sql-injection-safe</artifactId>
  <version>1.0.2</version>
</dependency>

 

이 다음에 아래와 같이 VO의 컬럼에 @SQLInjectionSafe를 추가합니다.

public class UserVo {
  private @SQLInjectionSafe String userId;
  private @SQLInjectionSafe String userName;
  
  // getter, setter 생략
}

 

그리고, 아래와 같이 스프링 컨트롤러에 전달되는 parameter에 @Valid를 추가하여 SQL Injection을 방어할 수 있습니다.

@RequestMapping(value  =  "/insertUser")
public @ResponseBody String insertUser(@Valid UserVo userVo) {
  // todo
}

 

여기까지 진행했다면, SQL Injection의 위험이 되는 문자가 있는 경우 BindException이 발생합니다.

728x90
loading