SQL Injection: 개념과 방어 방법
SQL Injection은 사용자가 입력한 데이터를 통해 데이터베이스에 비정상적인 SQL 쿼리를 주입하는 보안 취약점 공격입니다. 이를 통해 공격자는 데이터베이스의 민감한 데이터를 조회, 수정, 삭제하거나 시스템에 대한 제어권을 얻을 수 있습니다.
이 글에서는 SQL Injection의 개념과 바이패스 방법, 그리고 이를 방어하는 다양한 기법을 자바 예제와 함께 설명하겠습니다.
SQL Injection이란?
SQL Injection은 주로 다음과 같은 방식으로 발생합니다:
- 입력값을 SQL 쿼리 문자열에 그대로 삽입하여 실행.
- 쿼리의 논리를 변조하여 의도하지 않은 결과를 유도.
예시: 취약한 코드
String query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "';";
공격자가 username
에 admin' --
를 입력하면 쿼리는 다음과 같이 변조됩니다:
SELECT * FROM users WHERE username = 'admin' -- ' AND password = '';
--
는 SQL에서 주석 처리를 의미하므로 비밀번호 조건이 무시됩니다.
SQL Injection 바이패스 방법
SQL Injection 바이패스는 데이터베이스의 입력 검증과 로직을 우회하여 공격하는 기법입니다.
바이패스 방법 예시:
- 논리 우회:
- 입력값에 논리 연산자(
OR 1=1
)를 삽입하여 조건을 항상 참으로 만듦. - 예:
username=admin' OR 1=1 --
- 입력값에 논리 연산자(
- 유효성 검사 우회:
- 특수문자, 인코딩 기법을 활용하여 필터링 로직을 우회.
- 예:
admin' OR '1'='1
(문자열 비교 이용).
- 스키마 정보 노출:
- UNION 쿼리를 사용하여 추가적인 데이터베이스 정보를 조회.
- 예:
admin' UNION SELECT null, username, password FROM users --
SQL Injection 방어 방법
SQL Injection을 방지하기 위해 다음 기법을 사용할 수 있습니다.
1. 입력값 검증
입력값을 철저히 검증하여 예상치 못한 입력을 필터링합니다.
예제:
String username = request.getParameter("username");
String sanitizedUsername = username.replaceAll("[^a-zA-Z0-9]", "");
2. SQL 로직 검증
SQL 쿼리 작성 시 논리적 오류가 발생하지 않도록 구조를 점검합니다.
예제:
if (username.contains("'") || password.contains("'")) {
throw new IllegalArgumentException("Invalid characters in input");
}
3. Prepared Statement 사용
Prepared Statement는 파라미터화된 쿼리를 사용하여 SQL Injection 공격을 원천적으로 차단합니다.
Statement와의 차이점:
- Statement: 쿼리와 데이터를 결합하여 실행.
- Prepared Statement: 쿼리와 데이터를 분리하여 처리.
취약한 Statement 예제:
Statement stmt = connection.createStatement();
String query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "';";
ResultSet rs = stmt.executeQuery(query);
안전한 Prepared Statement 예제:
String query = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
4. ORM (Object-Relational Mapping) 사용
JPA, Hibernate 같은 ORM 프레임워크를 사용하여 SQL 쿼리를 직접 작성하지 않고 객체 지향적으로 데이터베이스와 상호작용.
예제:
@Entity
public class User {
@Id
private Long id;
private String username;
private String password;
}
public User findByUsernameAndPassword(String username, String password) {
return entityManager.createQuery(
"SELECT u FROM User u WHERE u.username = :username AND u.password = :password", User.class)
.setParameter("username", username)
.setParameter("password", password)
.getSingleResult();
}
마무리: SQL Injection 방어의 중요성
SQL Injection은 잘못된 입력값 처리를 통해 발생하는 심각한 보안 취약점입니다. 이를 방지하려면 입력값 검증, 로직 점검, 그리고 Prepared Statement와 같은 안전한 프로그래밍 기법을 활용해야 합니다. 보안을 염두에 두고 코드를 작성하는 습관을 들여 안전한 애플리케이션을 개발하세요!
'개발 부트캠프 > 백엔드' 카테고리의 다른 글
[Java] JSON (0) | 2025.01.16 |
---|---|
[Java] HTTP 요청 처리하기 (0) | 2025.01.16 |
[Java] 서블릿(Servlet) (0) | 2025.01.08 |
[Java] 계층형 아키텍처 패턴 (Layered Architecture Pattern) (0) | 2025.01.07 |
[Java] MVC 패턴 (1) | 2025.01.07 |