dev/solution
Mybatis ${}와 #{} 차이
오이호박참외
2024. 6. 26. 19:00
Mybatis에서 ${}와 #{}는 SQL 쿼리에서 파라미터를 다루는 방식의 차이다.
Mybatis ${}와 #{} 차이
${}: 파라미터를 문자열로 직접 치환. 주로 구조적 요소를 동적으로 설정 시 사용. SQL 인젝션에 취약.
#{}: 파라미터를 바인딩 변수로 사용. 주로 조건절, 값 설정 등에 사용. SQL 인젝션에 안전.
따라서, 가능하면 #{}를 사용하여 파라미터를 바인딩하는 것이 안전한 SQL 쿼리를 작성하는 데 도움이 된다.
${}
특징
- 문자열 대체
- 파라미터를 그대로 문자열로 치환
- SQL문이 생성될 때, 해당 위치에 파라미터 값이 그대로 삽입
- SQL injection에 매우 취약
용도
동적 SQL 생성:
- SQL 쿼리의 특정 부분을 동적으로 변경해야 할 때 사용
- 주로 테이블 이름, 컬럼 이름, ORDER BY 절 등 SQL 구문의 구조적 요소를 동적으로 설정할 때 유용
- 예를 들어, 특정 테이블에서 데이터를 조회할 때 테이블 이름을 동적으로 지정해야 하는 경우
<select id="selectFromTable" resultType="map">
SELECT * FROM ${tableName}
</select>
#{}
특징
- 파라미터를 SQL 쿼리에 바인딩 변수로 사용
- MyBatis가 이를 처리하여 Prepared Statement를 생성하고 파라미터 값을 안전하게 바인딩
- SQL 인젝션 공격에 대한 방어가 자동으로 이루어짐
용도
타입변환:
- JAVA의 Date 객체를 SQL의 DATE 타입으로 변환하는 경우에도 유용
- 아래와 같은 쿼리가 있을 때, name의 값이 "John"이라면
실제로 실행되는 SQL은 SELECT * FROM users WHERE name = ?가 되고, ?에는 "John"이 안전하게 바인딩됨
<select id="selectUserFromTable" resultType="map">
SELECT * FROM users WHERE name = #{name}
</select>
${}의 SQL Injection
이슈
실제 코드를 보다 보면 아래와 같이 작성한 경우가 분명 존재한다.
SELECT * FROM users WHERE name LIKE '%${name}%'
검색 영역에서 다음과 같은 소스를 사용했다면,
아래와 같은 검색어가 입력될 경우 database에 있는 모든 사용자 데이터가 검색 결과로 노출되는 문제가 발생한다.
' or (1=1)--
아래와 같이 쿼리가 실행된다.
조건절에 항상 참인 1=1로 인하여 모든 db의 값이 리턴되게 된다. -- 뒤는 주석 처리되는 모습이다.
SELECT * FROM users WHERE name LIKE '%' or (1=1)--%'
해결방안
아래와 같이 소스를 작성하는 습관을 들여야 한다.
SELECT * FROM users WHERE name LIKE CONCAT('%', #{name}, '%')
바인딩 변수를 사용하는 경우, 입력값은 데이터로 취급되며 쿼리 구조를 변경할 수 없다.
따라서, SQL 인젝션을 방지할 수 있다.