SQL injection(SQLi)은 웹 보안 취약점으로, 공격자가 application을 이용하여, 데이터베이스에 보내는 쿼리를 간섭하여 공격을 수행할 수 있는 취약점이다. 일반적으로 공격자는 일반적으로 검색을 통해 볼 수 없는 데이터를 볼 수 있다. 여기서 데이터는 다른 사용자가 가지고 있는 데이터이거나, applicaation 자체로 접근할 수 있는 다른 데이터가 포함되어 있을 수 있다. 대부분은 공격자는 이 데이터를 수정하거나, 삭제하여 application의 동작이나 content을 지속적으로 바꿀 수 있다.
경우에 따라 공격자는 SQL injection을 확대하여 기본 서버나 백엔드 인프라를 손상시키거나, 서비스 거부 공격을 수행할 수 있다.
SQL injection 공격이 성공하면 암호, 신용 카드 세부 내역, 개인 사용자 정보 등과 같은 중요한 데이터를 무단으로 접근할 수 있다. 최근 몇 년동안 발생한 많은 사건의 이목을 끈 데이터 침해는 SQL injection 공격의 인한 것이었고, 이로 인해 피해 회사들은 평판이 낮아지고, 벌금을 부과하게 되었다.(외국기준) 몇몇 경우에는 공격자가 조직 시스템에 영구적인 백도어를 획득해서 오랜 기간동안 장기적인 손상을 입힐 수 있다.
'
를 넣어서 오류 또는 기타 이상이 있는지 확인한다.or 1=1
, or 1=2
과 같은 boolean조건을 넣어서 application의 응답에 차이가 있는지 확인한다.대부분의 SQL injeciton 취약점은 select
문 where
절에서 발생한다.
그러나 SQL injection 취약점은 원칙적으로 쿼리 내의 모든 위치와 다양한 쿼리 유형 내에서 발생할 수 있다.
update
문에서, 업데이트 값 또는 where
절insert
문에서, 삽입된 값select
문에서, 테이블이나 column 이름select
문에서, order by
절다양한 상황에서 발생하는 다양한 SQL injection 취약점 공격과 기술이 있다. 일반적인 SQL injection 예는 다음과 같다.
다양한 카테고리의 제품을 표시하는 쇼핑 application을 생각했을 때, 사용자가 Gifts 카테고리를 클릭하면 브라우저에서에서 다음 URL을 요청한다.
https://insecure-website.com/products?category=Gifts
요청되면 application이 데이터베이스에서 관련 제품을 검색하기 위해 다음 SQL 쿼리를 실행한다.
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
이 SQL 쿼리는 데이터베이스에 다음을 반환되도록 요청이 된다.
released = 1
제한에 적용되어 출시하지 않은 제품을 숨기는데 사용되고, 출시되지 않은 제품의 경우 released = 0
로 가정된다.
application에 SQL injection 공격에 대한 방어를 구현하지 않으면, 공격자는 이런 공격을 구성할 수 있다.
https://insecure-website.com/products?category=Gifts'--
SQL 쿼리 결과
SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1
여기서 중요한 건 이중 대시 시퀀스 --
가 SQL의 주석 표시이며, 쿼리의 나머지 부분이 주석으로 해석되었다는 것을 의미한다. 이렇게 하면 나머지 부분이 제거되어서 더 이상 AND released = 1
을 포함하지 않는다. 즉 출시하지 않은 제품을 포함하여 모든 제품이 표시 된다는 의미이다.
더 나아가 공격자는 자신이 알지 못했던 카테고리를 포함하여 모든 카테고리의 모든 제품을 표시하도록 할 수 있다.
https://insecure-website.com/products?category=Gifts'+OR+1=1--
SQL 쿼리 결과
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1
수정된 쿼리는 category가 Gifts이거나 1이 1일 때 모든 항목을 반환한다. 1=1
는 항상 true이므로 쿼리는 모든 항목을 반환한다.
경고
조건문OR 1=1
을 SQL 쿼리에 넣을 때 주의한다. 위 문맥에서는 저 조건이 해를 끼치지 않을 수 있지만, 한 요청의 데이터를 여러 다른 쿼리에 사용되는 경우가 많다. 예를 들어UPDATE
문이나DELETE
문에 도달하면 데이터가 손실이 발생할 수 있다.
사용자가 사용자 이름과 비밀번호로 로그인할 수 있는 application을 생각했을 때, 사용자가 wiener
라는 사용자 이름과 bluecheese
라는 비밀번호를 제출하면 application은 다음 SQL 쿼리를 실행하여 credentials을 확인한다.
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
쿼리가 사용자의 세부 정보를 반환하면 로그인에 성공한 것이고, 그게 아니면 거부된 것이다.
여기서 공격자가 SQL 주석 시퀀스--
를 사용하여 쿼리 WHERE
절에서 암호 부분만 제거하면 암호 없이 모든 사용자로 로그인할 수 있다. 예를 들어 사용자 이름에 administrator'--
를 넣고 비밀번호 없이 제출하면 다음 쿼리가 생성된다.
SELECT * FROM users WHERE username = 'administrator'--' AND password = ''
이 쿼리는 사용자 이름이 administrator
인 사용자를 반환한다. 즉 공격자는 해당 사용자로 로그인을 성공한다.
SQL 쿼리의 결과가 application의 응답에 반환되는 경우, SQL injection 취약점을 이용해서 데이터베이스 내 다른 테이블에서 데이터를 검색할 수 있다. UNION을 사용하여 추가적인 SELECT문을 실행하고, 그 결과로 원본 쿼리에 추가되는 방식으로 작동된다.
예를 들어 application에서 사용자 입력에 “Gifts”가 들어가는 다음 쿼리가 실행될 경우
SELECT name, description FROM products WHERE category = 'Gifts'
그러면 공격자는 이렇게 입력값을 넣을 수 있다.
' UNION SELECT username, password FROM users--
이렇게 하면 application이 제품 이름, 설명과 모든 사용자의 이름, 비밀번호를 반환한다.
SQL injection의 대부분은 Blind 취약점이다. 즉 application의 응답 내에서 SQL 쿼리의 결과나 데이터베이스 오류에 대한 세부 정보를 반환하지 않는다는 것을 의미한다. Blind 취약점으로 데이터를 접근하는데 이용할 수 있지만, 그것에 사용되는 기술은 일반적으로 복잡하고 실행하기 어렵다.
취약점의 특성과 관련 데이터베이스에 따라 Blind SQL injection 취약점을 악용하는데 다음 기술을 사용할 수 있다.