심심한잉여의 잡동사니

[MyBatis] 샾(#{})과 달러(${})의 차이 본문

코딩일기/마이바티스

[MyBatis] 샾(#{})과 달러(${})의 차이

심심한잉여 2022. 5. 3. 14:49
반응형

마이바티스를 사용한 프로젝트에서 mapper.xml을 작성하다보면
보통은 샵(#{})을 통해 작성하게 되나 필요에 의해 달러(${})를 사용하기도 한다.
이 둘은 용도가 전혀 다르기 때문에 명확히 구분해서 사용하는 것이 좋다.


샵(#{})

<select id="test" resultType="String" parameterType="Map">

	SELECT
    	name AS name
    FROM
    	user
    WHERE
    	test = #{test}

</select>

샵을 사용한 경우 위 코드와 같은 예시로 작성을 주로하게 되며

Mybatis에서 위와 같은 샵(#{})을 사용한 쿼리문을 실행하게 되면서 PreparedStatement를 생성하게 되는데 이를 이용하게 되는데 #{}을 이용한 부분은 파싱되어 파싱된 쿼리문을 재활용하여 효율적으로 사용할 수 있게 된다.
그리고 변수에 작은 따옴표( ' ) 가 자동으로 붙어 쿼리가 수행되기 때문에 '#{test}' 처럼 쿼리문을 작성하지 않아도 된다.


달러(${})

달러(${})를 사용하게 되면 PreparedStatement를 생성하여 ?를 통해 값을 넣는게 아닌 값이 넣어진 채로 쿼리문이 수행된다.
그렇기 때문에 파라메터 값이 바뀔 때 마다 쿼리문 파싱을 진행해야 한다는 성능적 단점이 존재하지만 샵(#{})과는 달리 작은 따옴표( ' )가 붙지 않기 때문에 테이블명이나 컬럼명을 넘어 서브쿼리까지 동적으로 결정하여 사용할 수 있다.

<select id="select" resultType="String" parameterType="Map">
    SELECT
        ${test_col} AS name
    FROM
        ${T_test}
    WHERE
        id = #{test}
</select>

하지만 달러(${})의 경우 SQL Injection에 취약한 점이 흠이다.


SQL Injection

상황에 따라서 달라질 수 있겠으나 보안을 고려한다면 #{}을 사용해야 한다. 어떤 경우에 보안상 문제가 있냐면

<select id="selectUserFromTable" parameterType="Map" resultType="...">
    SELECT
        *
    FROM
        user
    WHERE
        id = '${id}' AND password = '${password}'
</select>

위와 같은 쿼리문이 있을 시 만일 ${id}에 대한 내용을 ( admin' -- ) 로 바꾸면 어떻게 되는지 상상해보자.

SELECT
    *
FROM
    user
WHERE
    id = 'admin' -- 'AND password = ''

위와 같이 password에 대한 부분이 사라지기 때문에 관리자 계정 정보를 바로 조회할 수 있게 되는것이다.

이처럼 달러(${})의 경우 샵(#{})을 사용하는 경우에 더 위험한 상황이 올 수 있다.

반응형