PreparedStatement와 MyBatis의 파라미터

PreparedStatement와 MyBatis의 파라미터

Feb 11, 2020    

PreparedStatement와 Statement

PreparedStatementStatement는 JDBC를 사용할 때 쿼리문을 작성하기 위해 사용한다. Statement는 파라미터로 받는 sql을 그대로 사용하고 PreparedStatement는 쿼리 파라미터를 다이나믹하게 받을 수 있다. 쿼리 파라미터는 select문의 where 조건 절, insert문의 value parameter 절에 사용한다. 그리고 컬럼의 타입에 따라 사용하는 메서드가 모두 다르다. (e.g. setInt, setString, …)

SQL Injection

위에서 설명한 것처럼 PreparedStatement는 파라미터의 타입체크가 들어가기 때문에 SQL Injection이 불가능하다. SQL Injection의 예로 아래와 같은 경우가 있을 것 같다. name 조건에 문자열이 들어가야 하는데 SQL Injection 공격으로 엉뚱한 쿼리가 실행되는 경우이다.

select * from foo where name = ; select 'sql injection' result; -- and id = 3;

PreparedStatement는 쿼리 파라미터의 타입을 지정하기 때문에 인젝션 공격에 안전하다.

실행계획?

오라클은 Cost Based Optimizer를 사용하는 경우, 쿼리 실행내역을 가지고 실행계획을 조정한다. 이 때 PreparedStatement로 작성한 쿼리는 오라클에서 하나의 쿼리에 바인드 변수로 묶여서 관리된다. 그러나 Statement를 사용하면 별개의 쿼리로 인식하기 때문에 쿼리 성능에 영향을 미칠 수 있다.

MyBatis의 파라미터

MyBatis의 해시(#)를 사용한 파라미터는 PreparedStatement의 파리미터와 대응한다. 그래서 SQL Injection 공격이 들어와도 안전하다.

이런 select 쿼리가 존재한다고 가정했을 때 이전 쿼리를 무시하고 새로운 쿼리를 시작하는 공격(; select 1 --)이 들어와도 쿼트 안에 스트링 값으로 취급되기 때문에 안전할 수 있다.

select
  name, id
from user
where name = #{name}
select
  name, id
from user
where name = '; select 1 --'

참고내용