Secure Coding Guide | SQL 삽입
정의
검증되지 않은 외부 입력 값이 SQL쿼리문 생성에 사용되어 악의적인 쿼리가 실행될 수 있는 보안약점이다.
웹에플리케이션에 대해서 가해지는 가장 흔한 공격 기법 중의 하나로 에플리케이션의 허점을 이용해서 데이터베이스를 비정상적으로 조작하는 기법이다.
영향
조작된 쿼리를 통해 DB 정보가 노출되거나 변조, 불법 로그인할 수 있다.
안전하지 않은 소스코드 예
안전하지 않은 Java 코드 일부
try {
String tableName = props.getProperty("jdbc.tableName");
String name = props.getProperty("jdbc.name");
String query = "SELECT * FROM " + tableName + " WHERE Name =" + name;
stmt = con.createStatement(query);
rs = stmt.executeQuery();
...
} catch (SQLException sqle) { ... } finally { ... }
tableName과 name의 값에 대해 대한 검증을 수행하지 않는다.
안전하지 않은 MyBatis xml 코드 일부
<select id="selectByUserId" resultType="com.devkuma.dto.User">
SELECT user_id,
FROM devkuma_user
WHERE user_id = '${userId}'
</select>
user_id = ‘${userId}’ 의 경우 외부에서 SQL 삽입이 가능할 경우 쿼리문의 구조가 변경된다.
잘못된 조치 방법
잘못된 조치방법
String tableName = props.getProperty("jdbc.tableName");
String name = props.getProperty("jdbc.name");
String query = "SELECT * FROM " + tableName + " WHERE Name =" + name;
stmt = con.prepareStatement(query);
rs = stmt.executeQuery();
...
PreparedStatement 를 사용하였으나, setString등의 상수 스트링을 이용하여 쿼리문의 구조가 변경 가능하다. 이는 잘못된 PreparedStatement 사용법이다.
안전한 소스코드
String tableName = props.getProperty("jdbc.tableName");
String name = props.getProperty("jdbc.name");
String query = "SELECT * FROM ? WHERE Name = ?";
stmt = con.prepareStatement(query);
stmt.setString(1, tableName); stmt.setString(2, name);
rs = stmt.executeQuery();
...
setString등의 상수 스트링을 이용하여 쿼리문 구조가 변경되지 않는 PreparedStatement클래 스를 이용한다.
<select id="selectByUserId" resultType="com.devkuma.dto.User">
SELECT user_id,
FROM devkuma_user
WHERE user_id = #{userId}
</select>
Mybatis 또는 iBatis의 sql map에 서 외부 입력이 쿼리로 구성되는 경우 ${..} 대신에 쿼리의 구조가 변경되지 않는 #{..}을 이용한다.
참고 자료
SQL삽입 취약점 제거를 위해 입력 필터링이 요구되는 특수문자
'" #-();@ =* /+
최종 수정 : 2018-05-27