2024.09.05.목.TIL JDBC, SQL Injection, XSS

김기남·2024년 9월 5일
post-thumbnail

안녕하세요, 오늘은 JDBC, SQL Injection, XSS 에 대해 정리해 보았습니다.

JDBC(Java DataBase Connectivity)

💡 자바 언어를 사용하여 DB와 상호 작용하기 위한 **자바 표준 API**(응용 프로그래밍 **인터페이스**) JDBC는 데이터베이스 관리 시스템(DBMS)과 통신하여 데이터를 삽입(C), 검색(R) , 수정(U) 및 삭제(D)할 수 있게 해주는 기술입니다.

Java 진영의 Database 연결 표준 인터페이스(JDBC)

JDBC의 주요 특징

  1. 표준 API
    1. 대부분의 RDBMS (관계형 데이터베이스 관리 시스템)에 대한 드라이버가 제공된다.
      이로써 여러 종류의 DB 대해 일관된 방식으로 상호 작용할 수 있다.
      ex) Database 종류가 바뀌어도 쿼리문이 실행되도록.
  2. 데터베이스 연결
  3. SQL 쿼리 실행
  4. Prepared Statement
  5. 결과 집합 처리(Result Set)
    1. 데이터베이스로부터 반환된 결과 집합을 처리할 수 있습니다.
      이를 통해 데이터를 조회하고 결과를 자바 객체로 매핑할 수 있습니다.
  6. 트랜잭션 관리
    1. JDBC를 사용하여 데이터베이스 트랜잭션을 시작, 커밋 또는 롤백하는 등의
      트랜잭션 관리 작업을 수행할 수 있습니다.

Statement

💡 DB와 연결되어 있는 Connection 객체를 통해 SQL문을 Database에 전달하여 실행하고, 결과를 반환받는 객체
public class StatementExample {
    public static void main(String[] args) {
        try {
						// ojdbc6.jar[oracle.jdbc.driver.OracleDriver] 파일을 라이브러리에 추가한다.
						
						// Driver연결
						Class.forName("oracle.jdbc.driver.OracleDriver");
						
						// Database와 연결(계정 접속)
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/mydatabase", "username", "password");
            
						// Statement 인스턴스 생성
						Statement statement = connection.createStatement();
            
						// String SQL Query
						
            String query = "SELECT * FROM MEMBER WHERE NAME = 'wonuk'";
            
						// Query 실행 -> 결과는 ResultSet으로 반환된다.
						ResultSet rs = statement.execute(query);
            
            // 결과 처리
						while (rs.next()) {
							// 결과 처리 로직
						}
            
						// 연결을 수동으로 끊어줘야한다.
						rs.close();
            statement.close();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
  • SQL 쿼리를 직접 문자열로 작성하여 데이터베이스에 보내는 방법
  • SQL 쿼리는 실행 전에 문자열 형태로 전달되고, 실행 시점에 데이터베이스에 직접 파싱되고 실행됩니다.
  • 매번 실행할 때마다 SQL 문을 다시 파싱하므로 성능에 영향을 미칠 수 있고, 보안 취약점을 가질 수 있습니다.

Prepared Statement

💡 SQL문을 Complie 단계에서 `?` 를 사용하여 preCompile 하여 미리 준비해놓고 Query문을 파라미터 바인딩 후 실행하고 결과를 반환받는다. 미리 준비해놓았다(Pre)! 가 핵심
public class PreparedStatementExample {
    public static void main(String[] args) {
        try {
						// ojdbc6.jar[oracle.jdbc.driver.OracleDriver] 파일을 라이브러리에 추가한다.
						Class.forName("oracle.jdbc.driver.OracleDriver");
						
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/mydatabase", "username", "password");
            String query = "SELECT * FROM employees WHERE department = ?";
            PreparedStatement preparedStatement = connection.prepareStatement(query);
            
            // 값을 설정
            preparedStatement.setString(1, "HR");
             
            ResultSet resultSet = preparedStatement.executeQuery();
            
            while (resultSet.next()) {
                // 결과 처리 코드
            }
            
            resultSet.close();
            preparedStatement.close();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
  • SQL 쿼리를 미리 컴파일하여 데이터베이스에 전송할 때 값만 바뀌는 형태로 전달합니다.
  • 쿼리가 한 번 컴파일되면 여러 번 실행할 수 있으며, 성능이 향상되고 보안 측면에서 더 안전합니다.
  • 동적인 입력값을 placeholder(?)로 대체한다.
    파라미터 바인딩을 통해 직접적으로 사용자 입력을 쿼리에 삽입하지 않는다.
  • 이스케이핑 : Escape 말그대로 탈출, 입력값이 자동으로 쿼리에 안전하게 이스케이핑됩니다.
    이스케이핑은 입력 데이터에서 잠재적인 SQL 쿼리 문자열을 무력화한다.

웹 보안(SQL Injection, XSS)

SQL Injection

💡 악의적인 사용자가 애플리케이션에서 입력 데이터를 이용하여 SQL 쿼리를 조작하고 데이터베이스에 무단 접근하거나 데이터를 변조하는 공격

SQL Injection 종류

  1. Error Based SQL Injection
    1. Database에 고의적으로 오류를 발생시켜 에러 출력을 통해 DB 구조를 파악하는 방법.
    2. 해결방법 : 클라이언트에게 에러 메세지 노출을 차단한다, 입력값을 Validation한다.
      Prepared Statements를 사용한다.
  2. Union Based SQL Injection
    1. 전제조건: 컬럼의 개수와 데이터 형식이 같아야 한다.
    2. DB의 UNION 연산자를 사용하여 쿼리 결과값의 조합을 통해 정보를 조회한다.
  3. Blind Based SQL Injection
  4. Stored Procedure SQL Injection
  5. Time Based SQL Injection

SQL Injection 예시

# 로그인 쿼리
SELECT * FROM MEMBER 
WHERE ID = ' " + 입력한id + " ' and " + "password = ' " + 입력한password + " ';"
# or 1=1로 항상 True가 되고 # 때문에 뒷부분 쿼리가 주석이된다.
# 즉, 항상 로그인이 된다.
SELECT * FROM MEMBER 
WHERE ID = 'WONUK or 1=1 #' and " + "password = 'tutor';"

Java 코드 예시

// 로그인
public String login(String id, String password) {
		return String query = 
			"SELECT * FROM MEMBER WHERE ID = " + id
			+ "AND PASSWORD = " + password;
}



// 검증
public String login(String id, String password) {
			// 매개변수 id, password 가 문제없는지 검증하는 로직 Escape 등
			
			String query = 
			"SELECT * FROM MEMBER WHERE ID = " + id + "AND PASSWORD = " + password;
			return query;
}

사실 우리는 이미 Prepared Statement를 사용하고 있었다

Spring JPA 사용시 Console Log에 출력되는 쿼리
설정을 통해 출력되지 않도록 할 수 있다.

****?(Placeholder) 에 파라미터 바인딩을 하는 모습을 볼 수 있다.

XSS(Cross Site Scription)

💡 악성 스크립트를 웹사이트에 주입하는 Code Injection 기법 중 하나 공격자가 웹 어플리케이션에 보낸 악성 코드가 다른 사용자에게 전달될 때 발생한다.
  • XSS의 종류
    • Stored XSS
      • 공격자가 취약점이 있는 Web Application에 악성 스크립트를
        영구적으로 저장하여 다른 사용자에게 전달하는 방식
      • ex) 게시판(HTML) 글 작성
<script>alert(document.cookie);</script>
  • 해당 script를 게시글에 삽입하면 HTML로 구성되어 있기 때문에
    해당 스크립트가 조회하는 사용자에게 실행되게 됩니다.
  • Reflected XSS
    • 외부 링크 페이지로 이동시킨다. ex) 메일 내 첨부된 링크 → 가짜 사이트로 연결
  • DOM based XSS

해결방법

  1. 입/출력 값을 검증하고 필터링하여 해결한다.
  2. 외부 보안관련 라이브러리를 사용한다.
  3. 보안 솔루션을 사용한다.

오늘의 카타카타

class Solution {

    public int solution(int n) {
        int answer = 0;
        if (n % 2 == 1) {
            while (n > 0) {
                if (n % 2 == 1) {
                    answer += n;
                    n--;
                } else {
                    n--;
                }
            }
        } else if (n % 2 == 0) {
            while (n > 0) {
                if (n % 2 == 0) {
                    answer += n * n;
                    n--;
                } else {
                    n--;
                }
            }
        }
        return answer;
    }
}

홀수면 n 이하 홀수인 값 모두 더하기
짝수면 n 이하 짝수인 값의 제곱 모두 더하기

profile
새로운 시작~!

0개의 댓글