DB 복제 지연과 SQL Injection(2)

SQL Injection

SQL 삽입은 악의적인 쿼리를 실행해서 데이터베이스를 비정상적으로 조작하는 code injection 공격 방법이다. SQL 삽입이 두 가지 조건이 충족될 때 가능하다. 이슈가 발생했던 애플리케이션은 두 가지 조건을 모두 충족하고 있었다.

  1. 웹 애플리케이션이 DB와 연동하고 있다.

  2. 외부 입력값이 DB 쿼리문으로 사용된다.

이번 이슈를 통해서 처음 SQL 삽입 쿼리문을 보게 되었는데 알아보니 SQL 삽입도 여러 공격 유형이 있었다.

쿼리 조건 무력화

Where 절을 우회시키기 위해서 조건이 참이 되도록 쿼리를 조작한다. 이번 이슈는 이 경우였다. 참이 되는 조건을 넣고 뒤의 쿼리는 주석이 되도록 --를 포함한 쿼리였다.

WHERE {column} = -1 OR 2+1-1-1=1 AND 853=853 -- '

여러 유형을 보다보니 값을 수정하거나 테이블을 삭제하는 경우도 있었는데 생각만 해도 정말 아찔했다. 아래의 예제처럼 user_id에 abc123' ; DELETE FROM users -- 을 넣게 되면 password에는 아무 값이나 넣어도 주석 처리가 되면서 users 테이블을 삭제하게 되는 것이다.

SELECT * FROM users WHERE user_id = 'abc123' ; DELETE FROM users -- AND password = 'abab';

에러 발생 후 정보 획득

의도적으로 에러가 발생하는 SQL 구문을 삽입하는 방식도 있다. 쿼리 수행 중에 오류가 발생하면 DB 오류를 그대로 브라우저에 출력하게 되면 이를 통해 스키마나 정보가 유출될 수 있다. 해커는 이를 가지고 또 다른 공격을 하기도 한다. UNION은 합쳐지는 테이블의 컬럼 개수가 일치해야만 오류가 나지 않는데 이를 이용한다면 아래와 같은 쿼리를 에러가 발생하지 않을 때까지 SELECT 다음 컬럼을 늘려가면서 users 테이블의 컬럼 수를 확인해볼 수 있다.

SELECT * FROM users WHERE user_id = 'test' UNION SELECT 1 -- AND password = 'abab';

만약 컬럼이 3개라는 걸 알아냈다면 MySQL이라면 information_scheme 데이터베이스를 이용하여 테이블 목록을 조회할 수 있다.

SELECT * FROM users WHERE user_ud = 'test' UNION SELECT TABLE_NAME, 1, 1, 1 FROM TABLES -- and password = 'abab';

Blind SQL Injection

위의 SQL 삽입 공격이 통하지 않을 때 사용하는 공격 기법으로 쿼리 결과의 참&거짓으로부터 DB 유출해낸다.

Boolean 기반 공격

쿼리의 결과를 참/거짓으로 나타내는 애플리케이션이 있을 때 이를 이용하여 데이터를 추측하는 공격 방법이다. AND 조건으로 알고 싶은 쿼리 조건을 사빕하면 그 결과로부터 데이터를 유출해낸다.

시간 기반 공격

응답 결과가 항상 동일할 경우, 시간을 지연시키는 쿼리를 삽입하여 응답 시간 차이로 참/거짓 여부를 판별한다. AND 조건에 sleep() 함수를 추가해 출력 결과가 지연되도록 해서 참/거짓을 구별할 수 있다. 조건이 참일 경우에는 sleep()으로 넘어가고, 거짓일 경우에는 결과가 바로 출력되므로 이를 통해 참/거짓을 알 수 있다.

SQL Injection 방어

SQL 삽입 공격은 대비할 수 여러 방법을 알아보도록 한다.

Prepared Statements

매개변수화된 쿼리를 사용하면 개발자가 SQL 쿼리문을 정의하고 나중에 매개변수를 쿼리에 전달하도록 하여 공격자가 SQL을 삽입하더라도 쿼리의 의도를 변경할 수 없다.

Error message

예외나 에러 메세지 등을 사용자가 볼 수 없도록 해야한다. 공격자들은 이런 메세지를 보고 오히려 힌트를 얻을 수 있기 때문이다. 에러가 발생했을 경우에는 문제가 발생했다는 상황만 사용자에게 전달되도록 한다.

유효성 검사

입력값의 유효성을 검사하는 것도 좋은 방법이 될 수 있다. SQL 삽입 공격에서 쓰이는 쿼리의 유형들을 검사하면 방지할 수 있다. SQL Injection Cheat Sheet 같은 것을 참고하면 더 좋을 것 같다.

Escape

쿼리에 입력하기 전에 사용자 입력을 이스케이프하는 방법도 있다. 각 DBMS는 특정 쿼리에 특정한 하나 이상의 문제 이스케이프 체계를 지원하여 이를 이용하면 SQL 삽입 공격을 막을 수 있다.

참고

위키피디아

박종명의 아름다운 개발 since 2010.06

OWASP Cheat Sheet Series - SQL Injection Prevcention Cheat Sheet