반응형
인젝션이란?
외부에서 입력된 데이터가 애플리케이션을 실행 흐름을 변경하거나, 보안 추약점을 악용할 수 있돌고 하는 공격 기법이다.
예를 들어 보안이 취한 검색 코드를 보여주겠다.
String query = "SELECT * FROM users WHERE username = '" + userInput + "'";
사용자가 admin' --을 입력하면?
SELECT * FROM users WHERE username = 'admin' --'
-- 이후는 주석 처리되어 전체 사용자 데이터가 노출될 수도 있다
1. SQL 인젝션 방지 원리
1. PreparedStatement 사용 ( 가장 기본적인 해결 방법)
- PreparedStatement는 SQL에 ? 플레이스홀더를 사용하여 안전하게 값을 바인딩 한다.
String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, userInput); // 사용자 입력값을 안전하게 바인딩
ResultSet rs = pstmt.executeQuery();
SQL과 입력값을 분리하여 해킹을 방지할 수 있음.
2. 사용자 입력값 검증 (Validation)
검색어가 너무 길거나, SQL 키워드(SELECT, DELETE 등)를 포함하면 차단해야 한다.
if (userInput.length() > 50 || userInput.matches(".*([';--]).*")) {
throw new IllegalArgumentException("잘못된 검색어입니다.");
}
특수문자(', ;, --) 포함 여부를 체크하여 SQL 공격을 방지!
3. 검색어가 없을 때 처리 (빈 검색어 방지)
검색 필드가 비어 있을 때 무조건 쿼리를 실행하면 성능 저하 또는 전체 데이터 유출 위험이 있다.
if (userInput == null || userInput.trim().isEmpty()) {
throw new IllegalArgumentException("검색어를 입력하세요.");
}
빈 검색어는 즉시 차단하여 불필요한 쿼리 실행 방지!
4. 대소문자 문제 해결 (LOWER() 또는 UPPER())
데이터베이스는 보통 대소문자를 구분하므로, 검색 시 동일한 결과를 얻기 위해 LOWER() 또는 UPPER()를 사용한다.
String sql = "SELECT * FROM users WHERE LOWER(username) = LOWER(?)";
PreparedStatement pstmt = connection.prepareStatement(sql); pstmt.setString(1, userInput);
모든 입력을 소문자로 변환하여 대소문자 구분 문제를 해결!
5. SQL 인덱스를 활용하여 성능 향상
검색어를 빠르게 찾기 위해 검색 대상 컬럼에 인덱스를 추가하면 성능이 개선
CREATE INDEX idx_username ON users(username);
인덱스를 추가하면 검색 속도가 빨라지고 데이터베이스 부하를 줄일 수 있다
정리 (SQL 인젝션 방지 원칙)
방법 및 설명
PreparedStatement | SQL과 입력값을 분리하여 해킹 방지 |
사용자 입력 검증 | SQL 특수문자(', --) 차단 |
빈 검색어 방지 | 불필요한 쿼리 실행 방지 |
대소문자 변환 | LOWER(), UPPER()를 활용하여 검색 일관성 유지 |
SQL 인덱스 사용 | 검색 속도를 향상하여 성능 개선 |
결론
- 검색 기능에서 SQL 인젝션 방지는 필수!
- PreparedStatement, 입력 검증, 빈 검색어 체크로 보안 강화!
- LOWER(), UPPER() 활용 및 인덱스로 성능까지 개선!