반응형
반응형
SQL 인젝션(SQL Injection)은 데이터베이스를 사용하는 웹 애플리케이션에서 발생하는 보안 취약점 중 하나로, 공격자가 악의적인 SQL 코드를 삽입하여 애플리케이션의 데이터베이스를 조작하거나, 데이터를 불법적으로 조회·수정·삭제하는 공격 기법이다.
SQL 인젝션이 어떻게 발생하는건가?
SQL 인젝션은 주로 애플리케이션에서 사용자로부터 입력받은 값이 SQL 쿼리에 안전하게 처리되지 않고 그대로 삽입될 때 발생하며, 공격자는 여기에 SQL 구문을 추가하여 애플리케이션이 의도하지 않은 동작을 하도록 만들 수 있다.
예시를 들어보겠다.
어떠한 로그인 폼에 사용자 ID , 비밀번호를 입력하는 란이 있다고 가정해보자.
SELECT * FROM users WHERE username = '사용자입력' AND password = '사용자입력';
여기서 username과 password는 사용자가 입력한 값이 그대로 들어가는 자리이며,
만약 공격자가 username에 ' OR '1'='1이라는 값을 입력한다면, 쿼리는 다음과 같이 변경된다.
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '';
이 쿼리는 username이 빈 문자열이거나, '1'='1'이라는 조건이 참인지 확인하는 쿼리로 변환되며,
SQL에서 '1'='1'은 항상 참이므로, 공격자는 실제로 비밀번호를 모른다고 해도 로그인에 성공할 수 있게 된다.
이러한 문제를 생각해보자.
SQL 인젝션의 위험성
SQL 인젝션을 악용하면 다음과 같은 위험이 발생할 수 있다.
- 데이터 유출: 공격자는 사용자 정보를 포함한 민감한 데이터를 조회할 수 있음.
- 데이터 조작: 공격자는 데이터를 임의로 수정, 삭제하거나, 새로운 데이터를 삽입할 수 있음.
- 시스템 권한 탈취: SQL 인젝션을 통해 데이터베이스 서버의 권한을 탈취하여 무슨짓을 할지 모름.
- 애플리케이션 파괴: 악의적인 쿼리를 삽입하여 데이터베이스를 손상시키거나, 서비스 중단을 시켜버릴수도 있다.
이러한 SQL인젝션을 방어하기 위해서는 여러가지 방법이 있다. 한번 예시로 같이 봐보자.
SQL 인젝션 방어 방법
- Prepared Statement (준비된 구문) 사용
Prepared Statement는 SQL 쿼리에서 사용자의 입력값을 변수로 처리하고, 이를 SQL 구문과 별도로 취급하여 SQL 인젝션을 방지할 수 있다.
여기서 ?는 실제 사용자 입력값이 들어가는 자리인데, 이 값을 따로 처리하므로 SQL 인젝션이 발생할 가능성이 없다.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();
- 입력 값 검증
사용자가 입력한 값이 예상되는 데이터 형식인지 확인하고, 의심스러운 문자나 SQL 구문을 포함하지 않도록 제한한다. 예를 들어, 숫자를 입력해야 하는 곳에는 문자나 특수문자가 들어가지 않도록 검증한다.public class InputValidation { public static boolean isValidNumber(String input) { // 숫자만 허용하는 정규식 return input.matches("\\d+"); // 정규식: 0-9까지의 숫자 } public static void main(String[] args) { String userInput = "1234"; if (isValidNumber(userInput)) { System.out.println("유효한 입력입니다."); } else { System.out.println("유효하지 않은 입력입니다."); } } }
- ORM 사용
Object-Relational Mapping(ORM) 프레임워크를 사용하면 SQL 쿼리를 직접 작성하지 않고도 데이터베이스에 접근할 수 있습니다. 이로 인해 SQL 인젝션 공격에 더 안전할 수 있으며, Java에서는 Hibernate 같은 ORM 도구를 사용할 수 있다.// Hibernate Entity 클래스 @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "username", nullable = false) private String username; @Column(name = "password", nullable = false) private String password; // Getter, Setter, Constructor 등 } // Hibernate를 사용한 데이터 조회 예시 public class UserDao { public User findUserByUsername(String username) { // HQL (Hibernate Query Language)을 사용 String hql = "FROM User WHERE username = :username"; Session session = HibernateUtil.getSessionFactory().openSession(); Query query = session.createQuery(hql); query.setParameter("username", username); User user = (User) query.uniqueResult(); session.close(); return user; } }
- 데이터베이스 권한 최소화
애플리케이션이 사용하는 데이터베이스 계정의 권한을 최소한으로 설정한다. 예를 들어, 단순 조회만 필요한 경우에는 쓰기 권한을 제거한다.-- 데이터베이스에 읽기 전용 사용자 생성 CREATE USER read_only_user IDENTIFIED BY 'password'; -- 테이블 조회 권한만 부여 GRANT SELECT ON your_table TO read_only_user; -- 다른 권한(INSERT, UPDATE, DELETE 등)을 제거하여 읽기 전용으로 설정 REVOKE INSERT, UPDATE, DELETE ON your_table FROM read_only_user;
- 에러 메시지 노출 방지
데이터베이스 에러 메시지가 사용자의 화면에 그대로 출력되지 않도록 조치하여, 공격자가 시스템 구조를 유추할 수 없게 한다.
public class ErrorHandling {
public static void main(String[] args) {
try {
// 데이터베이스에 연결하고 쿼리 실행하는 로직 (예시)
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM non_existent_table"); // 없는 테이블 조회
} catch (SQLException e) {
// 사용자에게는 일반적인 오류 메시지만 보여줌
System.out.println("오류가 발생했습니다. 나중에 다시 시도해주세요.");
// 실제 에러는 로그 파일 등에 기록하여 내부적으로 분석할 수 있게 함
e.printStackTrace(); // 실제 오류 내용을 서버 로그에 출력
}
}
}
다시 한 번 SQL 인젝션을 예시로 들어서 한번 또 보자.
//공격 전
SELECT * FROM users WHERE username = 'john' AND password = 'mypassword';
// 공격 후 (SQL 인젝션 적용)
SELECT * FROM users WHERE username = '' OR '1'='1' -- AND password = '';
SQL 인젝션은 매우 위험하지만, 수 많은 방법중 적절히 방어 방법을 사용하면 충분히 예방할 수 있으며, Prepared Statement와 입력 값 검증 등 기본적인 보안 조치를 하는 것이 중요한 것 같다.
반응형
'보안' 카테고리의 다른 글
[CSP] content-security-policy header not set 해결 (0) | 2024.09.28 |
---|---|
[보안] 10가지 보안 솔루션 각 솔루션의 기능과 목적 (1) | 2024.09.19 |
[SamSite] SameSite란? (0) | 2024.09.09 |
[CSRF] CSRF(Cross-Site Request Forgery)란? (1) | 2024.09.09 |