회사 입사했을때부터 당연스럽게 써왔던 #{}
다른 방법도 있을거라고 생각도 못했는데 최근 알아버린 사실이 있었으니..
마이바티스(MyBatis)를 사용하는 프로젝트에서 mapper 쿼리문이 담긴 XML 파일을 보면
XML에 쿼리문을 작성할 때 파라미터 값을 설정하게 될텐데 이때 ${}과 #{}를 사용하게 된다.
이 둘은 용도가 다르므로 명확하게 구분하여 사용 해야 한다! (보안을 고려한다면 #{}를 사용)
| #{ } | ${ } | |
| 1 | 파싱된 쿼리문이 재활용(캐싱)되기 때문에 효율적 | (성능상의 단점) 값이 넣어진 채로 쿼리문이 수행되기 때문에 파라미터의 값이 바뀔 때마다 항상 쿼리문 파싱을 진행 |
| 2 | *SQL Injection을 방어(*PreparedStatement 방식으로 수행) | *SQL Injection에 취약 |
| 3 | 변수에 작은 따옴표(‘)가 자동으로 붙여져서 쿼리가 수행되기 때문에 table_1, table_2 에 대해 table_#{tableId} 같은 식으로 쿼리문을 작성할 수 없음 → SQLSyntaxErrorException 오류 발생 |
작은 따옴표(‘)가 붙지 않기 때문에 *아래 예시처럼 테이블 이름이나 컬럼 이름을 동적으로 결정할 때 사용할수 있음 |
(1) * SQL Injection (SQL 삽입공격) 이란?
SELECT * FROM Users WHERE id = '${id}' AND password = '${password}'
SELECT * FROM Users WHERE id = '${id}' 'OR 1=1 -- AND password = '${password}'
- 위와 같은 쿼리문을 실행할 때, 악의적인 사용자가 SQL 구문('OR 1=1 --)을 주입하게 되면 where절에 있는 싱글쿼터를 닫아주기 위한 싱글쿼터(')와 추가 조건 (OR 1=1), 그리고 패스워드 조건 절은 주석(--)처리 해줌으로 비밀번호 없이 로그인이 가능해진다.
(2) * PreparedStatement 이란?
- 데이터베이스 관리 시스템(DBMS)에서 동일하거나 비슷한 데이터베이스 문을 높은 효율성으로 반복적으로 실행하기 위해 사용되는 기능을 말한다.
(3) * 예시
-- 1
SELECT name, email FROM User WHERE id = #{id}
-- 2
SELECT name FROM user_#{tableId} WHERE id = #{id}
-- 3
SELECT name, email FROM User WHERE Id = ${id}
- 1. 쿼리문을 작성할 때 #{ }을 사용하는 경우, WHERE id = ? 파라미터가 바인딩되어 수행되며,
변수에 작은 따옴표(‘)가 자동으로 붙여 쿼리가 수행되기 때문에 '#{id}'와 같은 식으로 쿼리문을 작성하지 않아도 된다.
- 2. 테이블 설계가 user_1, user_2과 같이 분리되어 구성되어 있을 때에는 user_#{tableId}로 작성할 수 없다.
위 쿼리문이 수행되면 tableId 변수 양쪽에 따옴표가 붙기 때문에 SQLSyntaxErrorException 오류가 발생한다.
- 3. ${ } 는 #{}을 사용한 것과 다르게 값이 넣어진 채로 쿼리문이 수행되며,
그렇기 때문에 파라미터의 값이 바뀔 때마다 항상 쿼리문 파싱을 진행해야 한다.
작은 따옴표(‘)가 붙지 않기 때문에 -- 2 의 예시처럼 테이블 이름이나 컬럼 이름을 동적으로 결정할 때 사용할 수 있다.
'개발기본지식' 카테고리의 다른 글
| [Mybatis] 스프링 부트 mybatis 에러 (Mapped Statements collection does not contain value for~) (1) | 2024.04.01 |
|---|---|
| 크로스 도메인 에러 (Cross-Domain 이란?) (0) | 2024.03.25 |