[mybatis] 파라메터 ${}, #{} 차이점 정리

${}, #{}

mybatis mapper에서 parameter를 받아서 사용할때 크게 2가지 방법이 있다.
${}, #{} 두가지 방법은 동작이 다르고 경우에따라서는 보안상으로 좋지 않으므로 차이점을 명확히 알고 사용해야한다.

  • ${} : 원문 그대로 -> 잠재적 sql injection 취약점 - 주의해서 사용
  • #{} : ' ' 를 씌워줌, sql injection 방지

파라메터 - Parameters

Parameters는 마이바티스에서 매우 중요한 엘리먼트이다. 대략 90%이상은 간단한 경우 이러한 형태로 설정한다.

1
2
3
4
5
<select id="selectUsers" resultType="User">
select id, username, password
from users
where id = #{id}
</select>

#{} 문법은 마이바티스로 하여금 PreparedStatement프로퍼티를 만들어서 PreparedStatement파라미터(예를들면 ?)에 값을 셋팅하도록 할 것이다. 위의 쿼리로 예를 들면

1
2
3
select id, username, password
from users
where id = ?

이후 ? 에 값을 대입한다. ( ' 도 같이 추가해준다. )
이때 ? 에 들어올 데이터가 달라지더라도 mysql같은 rdb에서 동일한 쿼리로 인식한다
따라서 1,2,3,4, 값이 바뀌어도 새로 파싱을 하지 않는다.

아래와같은 문법으로 type을 지정해줄수도 있다

1
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

문자열 대체 String Substitution

가끔은 SQL 구문에 변하지 않는 값으로 삽입하길 원하기도 한다. 예를들면 ORDER BY와 같은 구문들이다. 이럴때는 #{} 을 사용하면 string 에 따옴표를 추가하므로 문법 오류가 발생 할 수 있다.
이런경우 ${} 를 사용할 수 있다.

1
ORDER BY ${columnName}

마이바티스는 문자열을 변경하거나 이스케이프 처리하지 않는다.
사용자 입력값에 대해서는 언제나 자체적으로 이스케이프 처리하고 체크해야 한다.

정적 바인딩

1
2
3
4
5
<select id="selectUsers" resultType="User">
select id, username, password
from users
where id = ${id}
</select>

${} 로 바인딩을 하게되면 정적으로 쿼리에 값이 들어가게 되는데

1
2
3
select id, username, password
from users
where id = 1
1
2
3
select id, username, password
from users
where id = 2

이경우 값이 바뀌면 쿼리가 여러개 생성된다. 그리고 파싱도 여러번 하게되므로 성능상 #{} 보다 불리하다

위험성

사용자 입력값에 대해서는 이 방법을 사용하면 안된다.

만약 이 값이 사용자의 입력을 통해 전달된다면 위험 할 수 있다.
사용자가 입력한 값이 그대로 쿼리에 적용되기 때문이다. 잠재적인 SQL 주입 공격에 노출된다.

참고자료

https://mybatis.org/mybatis-3/sqlmap-xml.html

Comments