유저가 제공하는 URL 파라미터와 같은 데이터는, 항상 신뢰할수 없고, 손상된 데이터로 간주해야 합니다.
손상된 데이터를 통해 SQL 쿼리를 생성하는 것은, 쿼리의 초기 의미와는 다르게 공격자들이 특별하게 조작된 값을 삽입할 수 있게 합니다.
데이터베이스 쿼리 인젝션 공격이 성공하면 데이터베이스의 민감한 정보들을 읽고, 수정하고, 삭제할 수 있으며 심지어는 데이터베이스를 종료하거나, 임의의 OS 커맨드를 실행할 수 있습니다.
일반적으로, 해결책은 prepared statements 를 사용하고, SQL 쿼리 파라미터를 setString 과 같은 전용 메소드를 사용해 사용자가 제공한 데이터를 적절하게 처리한 채로 바인딩해야합니다.
다른 방법은 모든 파라미터를 쿼리를 생성할 때 검증하는 것입니다.
이것은 String 값은 원시 타입으로 변경하거나, 사용 가능한 값을 white list 로 관리하여 검증하는 것으로 달성할 수 있습니다.
이 룰은 JDBC, Java EE Entity Manager, Spring Framework, Hibernate, JDO, Android Database, Apache Torque, Apache Turbine, MyBastis, Rapidoid 를 지원합니다.
규칙을 어긴 코드
public boolean authenticate(javax.servlet.http.HttpServletRequest request, java.sql.Connection connection) throws SQLException {
String user = request.getParameter("user");
String pass = request.getParameter("pass");
String query = "SELECT * FROM users WHERE user = '" + user + "' AND pass = '" + pass + "'"; // Unsafe
// 만약 특별한 값인 "foo' OR 1=1 --" 이 user = 혹은 pass = 의 인자로 전달된다면, 인증은 바이패스됩니다.
// 실제로, 이 값이 유저로 전달된다면 쿼리는 다음과 같습니다.
// SELECT * FROM users WHERE user = 'foo' OR 1=1 --' AND pass = '...'
// '--' 는 SQL 의 끝 라인까지 주석이므로 쿼리는 아래와 동일합니다.
// SELECT * FROM users WHERE user = 'foo' OR 1=1
// 해당 쿼리는 아래와 동일하게 되고,
// SELECT * FROM users WHERE 1=1
// 이것은 아래의 쿼리와 같습니다.
// SELECT * FROM users
java.sql.Statement statement = connection.createStatement();
java.sql.ResultSet resultSet = statement.executeQuery(query); // 규칙을 준수하지 않은 코드
return resultSet.next();
}
규칙을 준수한 해결책
public boolean authenticate(javax.servlet.http.HttpServletRequest request, java.sql.Connection connection) throws SQLException {
String user = request.getParameter("user");
String pass = request.getParameter("pass");
String query = "SELECT * FROM users WHERE user = ? AND pass = ?"; // authenticate() 메소드가 이러한 상황에 여전히 무차별 공격에 취약하더라도, 안전합니다.
java.sql.PreparedStatement statement = connection.prepareStatement(query);
statement.setString(1, user); // 적절하게 escaped 됩니다.
statement.setString(2, pass);
java.sql.ResultSet resultSet = statement.executeQuery();
return resultSet.next();
}
참고
- OWASP Top 10 2021 Category A3 - Injection
- OWASP Top 10 2017 Category A1 - Injection
- MITRE, CWE-20 - Improper Input Validation
- MITRE, CWE-89 - Improper Neutralization of Special Elements used in an SQL Command
- MITRE, CWE-564 - SQL Injection: Hibernate
- MITRE, CWE-943 - Improper Neutralization of Special Elements in Data Query Logic
- OWASP SQL Injection Prevention Cheat Sheet
- CERT, IDS00-J. - Prevent SQL injection
- SANS Top 25 - Insecure Interaction Between Components
If you like SONARKUBE, don’t forget to give me a star.