SQL Injection 방지 방법 및 예제

SQL Injection은 웹 애플리케이션이 사용자 입력을 적절히 검증하거나 필터링하지 않아 발생하는 보안 취약점입니다. 공격자는 미리 정의된 SQL 쿼리 뒤에 추가적인 SQL 문장을 삽입하여 데이터베이스를 조작할 수 있습니다. 이를 통해 권한 없는 쿼리를 실행하고 중요한 데이터를 탈취할 수 있습니다. 아래는 SQL Injection의 기본 원리를 설명하기 위한 테스트 코드입니다. ### 데이터베이스 설정 db.properties 파일:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/exampledb?useUnicode=true&characterEncoding=utf8&useSSL=false
username=exampleuser
password=examplepass
### JdbcUtils.java (데이터베이스 연결 유틸리티)

public class DatabaseConnector {
    private static String driver;
    private static String url;
    private static String username;
    private static String password;

    static {
        try {
            InputStream input = DatabaseConnector.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(input);

            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            Class.forName(driver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static java.sql.Connection connect() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }

    public static void closeResources(java.sql.Connection conn, Statement stmt, ResultSet rs) {
        if (rs != null) {
            try { rs.close(); } catch (SQLException ignored) {}
        }
        if (stmt != null) {
            try { stmt.close(); } catch (SQLException ignored) {}
        }
        if (conn != null) {
            try { conn.close(); } catch (SQLException ignored) {}
        }
    }
}
### 문제 있는 로그인 코드 (SQL Injection 위험)

public class VulnerableLogin {
    public static void main(String[] args) {
        authenticate("' OR '1'='1", "irrelevant"); // SQL Injection 시도
    }

    public static void authenticate(String id, String pwd) {
        java.sql.Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseConnector.connect();
            stmt = conn.createStatement();
            String query = "SELECT * FROM users WHERE username='" + id + "' AND password='" + pwd + "'";
            rs = stmt.executeQuery(query);

            if (rs.next()) {
                System.out.println("로그인 성공: " + rs.getString("username"));
            } else {
                System.out.println("로그인 실패");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DatabaseConnector.closeResources(conn, stmt, rs);
        }
    }
}
위 코드에서 사용자가 `' OR '1'='1`와 같은 값을 입력하면 모든 사용자 정보가 노출될 수 있습니다. ### 해결책: PreparedStatement 활용 PreparedStatement는 SQL Injection을 방지하며 성능도 개선합니다. 아래는 안전한 로그인 코드의 예시입니다.

public class SecureLogin {
    public static void main(String[] args) {
        authenticate("' OR '1'='1", "irrelevant"); // 이제 Injection 공격 무효화됨
    }

    public static void authenticate(String id, String pwd) {
        java.sql.Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            conn = DatabaseConnector.connect();
            String query = "SELECT * FROM users WHERE username=? AND password=?";
            pstmt = conn.prepareStatement(query);
            pstmt.setString(1, id);
            pstmt.setString(2, pwd);

            rs = pstmt.executeQuery();

            if (rs.next()) {
                System.out.println("로그인 성공: " + rs.getString("username"));
            } else {
                System.out.println("로그인 실패");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DatabaseConnector.closeResources(conn, pstmt, rs);
        }
    }
}
이렇게 하면 사용자의 입력값이 쿼리문 자체에 직접 포함되지 않으므로 SQL Injection 공격을 방지할 수 있습니다.

태그: SQLInjection PreparedStatement JDBC

5월 26일 15:49에 게시됨