본문 바로가기
Database

[Database] SQL Injection

by yonikim 2025. 1. 9.
728x90

 

SQL Injection이란?

데이터베이스와 연동된 웹 애플리케이션에서 공격자가 입력 폼 또는 URL 입력란에 SQL 구문을 삽입하여 DB 를 조작할 수 있는 취약점을 의미한다. 

주로 사용자가 입력한 데이터를 제대로 filtering, escaping하지 못했을 경우에 발생한다.

 

공격 종류 및 방법

1. Classic SQL Injection 

사용자 입력값을 그대로 SQL 쿼리에 삽입하여 악의적인 SQL 쿼리를 실행하는 기본적인 공격 방법이다. 

 

로그인 공격 예시

로그인 페이지가 있고, 로그인을 할 때 USER_ID 와 USER_PASSWORD 를 입력받아 로그인이 진행된다고 했을 때, 

 

기본 쿼리문 

SELECT user FROM Users WHERE user_id = 'USER_ID' AND user_password = 'USER_PASSWORD';

 

공격 예시: 로그인 창의 ID 부분에 'OR 1=1 -- 를 입력 

SELECT user FROM Users WHERE user_id = '' OR 1 = 1 --'USER_ID' AND user_password = 'USER_PASSWORD';
  • WHERE 절에 있는 싱글 쿼터(')를 닫아주고,
  • OR 1=1 로 모두 참을 만들어 준 후
  • --를 이용해 그 뒤의 모든 쿼리문을 주석처리 한다.

결과적으로 Users 테이블에 있는 모든 정보를 조회하게 되며 가장 먼저 만들어진 계정(보통 관리자 계정)으로 로그인할 수 있게 되어 관리자 계정을 탈취하게 된다.

 

 

2. Blind SQL Injection 

공격자가 데이터베이스의 데이터를 직접 조회하지 않고, 참/거짓의 결과를 통해 정보를 추출하는 방법이다. 

 

Boolean 기반 공격 예시

기본 쿼리문 

SELECT user FROM Users WHERE user_id = 'USER_ID' AND user_password = 'USER_PASSWORD';

 

공격 예시: 로그인 폼에 DB 테이블명을 알아내기 위한 쿼리문을 주입, 이때 임의로 가입한 id3이라는 아이디와 함께 구문을 주입 

SELECT user FROM Users WHERE user_id = 'id3' AND ASCII(SUBSTR((SELECT name FROM information_schema.tables WHERE table_type='base table' limit 0,1),1,1)) > 100 -- USRE_ID' AND user_password = 'USER_PASSWORD';

 

  • limit 키워드를 통해 하나의 테이블만 조회하고, SUBSTR 함수로 첫 글자만 찾게 된다. 
  • ASCII를 통해 값이 변환되고 조회디는 테이블명의 첫번째 글자가 U면 테이블이 조회된다.
  • True(로그인)이 될 때까지 100 숫자를 변경하며 비교를 하게 된다. 
  • 자동화 스크립트로 만들어 단기간 내에 테이블 명을 알아낼 수도 있다.

 

Time 기반 공격 예시 

기본 쿼리문

SELECT user FROM Users WHERE user_id = 'USER_ID' AND user_password = 'USER_PASSWORD';

 

공격 예시

SELECT user FROM Users WHERE user_id = 'id3' OR (LENGTH(DATABASE())=1 AND SLEEP(2)) -- USER_ID' AND user_password = 'USER_PASSWORD';
  • 숫자 1을 조작해 현재 사용하고 있는 데이터베이스의 길이를 알아낼 수 있다.
  • LENGTH를 사용해 문자열 길이를 반환하도록 한다.
  • DATABASE()를 사용해 데이터베이스의 이름을 반환한다. 

 

3. Union based SQL Injection 

UNION SQL 연산자를 사용하여 원래의 쿼리 결과에 추가적인 SELECT 결과를 결합하는 방법이다.

 

게시글 조회 공격 예시 

게시판이 있고, 게시글을 검색할 때 INPUT 을 받아 검색이 진행된다고 했을 때, 

 

기본 쿼리문

SELECT * FROM Board WHERE title LIKE '%INPUT%' OR contents LIKE '%INPUT%';

 

공격 예시: 검색 창에 'UNION SELECT null, id, password FROM Users -- 를 입력 

SELECT * FROM Board WHERE title LIKE '%' UNION SELECT null, id, password FROM Users --%' OR contents LIKE '%INPUT%';

 

사전 공격을 통해 컬럼명과 테이블명을 얻은 후 사용자의 ID와 PW를 요청하는 쿼리문을 함께 입력하게 되면 사용자의 개인 정보가 게시글과 함께 보이게 된다.

 

 

4. Error based SQL Injection

데이터베이스가 에러 메시지를 반환할 때, 그 메시지를 통해 데이터베이스의 정보를 추출하는 방법이다.

공격 예시: CAST 와 같은 함수를 사용하여 강제적으로 에러를 발생시키고, 해당 에러 메시지에서 데이터베이스의 정보를 추출한다.

 

 

대응 방법

1. 입력값 검증 

  • ', ", #, --, = 등 특수문자와 명령어 필터링
  • 데이터 길이 제한

2. Prepared Statement 사용

 

3. SQL 서버 오류 발생시 해당하는 에러 메시지 감추기

 

4. 데이터베이스의 권한 제한

-- 원본 테이블 예시: Users
CREATE TABLE Users (
    UserID INT PRIMARY KEY,
    UserName VARCHAR(100),
    UserEmail VARCHAR(100)
);

-- 뷰 생성
CREATE VIEW PublicUsers AS
SELECT UserName, UserEmail
FROM Users;

-- 사용자는 이 뷰를 통해서만 데이터를 조회
SELECT * FROM PublicUsers;

 

5. 웹 방화벽(WAF)을 사용하여 비정상적인 데이터가 전송될 경우 차단

 

 

 

[References]

https://velog.io/@33bini/DB-SQL-Injection

https://velog.io/@k4minseung/DB-SQL-Injection-%EA%B3%B5%EA%B2%A9%EA%B3%BC-%EB%B0%A9%EC%96%B4-%EB%B0%A9%EB%B2%95

 

728x90

'Database' 카테고리의 다른 글

[MySQL] 트랜잭션 격리 수준  (0) 2025.01.19
[MySQL] 트랜잭션 (Transaction)  (1) 2024.01.05
[Mongo] 백업 및 복원하기  (0) 2021.08.27