서비스에서 닉네임, 번호 등을 입력하는 아래와 같은 형태의 SQL이 있다고 가정하자.
이 SQL문은 UserId에 따라 한 명의 유저를 조회하기 위한 것으로서, txtSQL은 유저의 입력값에 따라 완성된다.
txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
만약 '잘못된 입력값'을 방지할 대책이 세워져 있지 않다면, 유저는 UserId
로 105 OR 1=1
과 같은 값을 의도적으로 입력할 수 있다. 그러면 SQL문은 아래와 같이 되고, 이는 OR 1=1
이 항상 참이기 때문에 모든 유저 정보를 가져올 것이다.
SELECT * FROM Users WHERE UserId = 105 OR 1=1;
만약 테이블에 실명, 연락처, 비밀번호 등의 개인정보가 들어잇다면, 심각한 유출 사고가 일어날 것이다.
유저로부터 이름
, 패스워드
를 입력받아 유저 조회에 사용한다고 가정해 보자.
uName = getRequestString("username");
uPass = getRequestString("userpassword");
sql = 'SELECT * FROM Users WHERE Name ="' + uName + '" AND Pass ="' + uPass + '"'
// 올바르게 완성될 sql은 다음과 같다.
// SELECT * FROM Users WHERE Name = Name ="John Doe" AND Pass ="myPass"
만약 어떤 해커가 input box에 " or ""="
와 같이 값을 입력한다면, SQL은 다음과 같이 완성될 것이다.
SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""
OR ""=""
는 항상 True이기 때문에, 위 SQL은 유효한 것이고 Users 테이블의 모든 행을 다 조회할 것이다.
Batched SQL Statements이란, 세미콜론으로 구분된 2개 이상의 SQL문 묶음을 의미한다.
비슷한 형태로 Stored Procedure도 있다. Stored Procedure는 일련의 쿼리들을 모아 하나의 함수처럼 사용하기 위한 것이다.
(ex)
SELECT * FROM Users; DROP TABLE Suppliers
다음과 같이 조회 쿼리를 준비한다고 가정해 보자.
txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
그리고 만약 해커가 UserId
로 105; DROP TABLE Suppliers
를 입력한다면, 다음과 같이 Batched SQL이 완성되어 연쇄적으로 실행된다.
SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers;
이 공격으로 인해 Suppliers 테이블은 삭제될 것이다.
SQL 파라미터란, 실행 시점에 SQL 쿼리에 추가되는 값이다.
SQL 파라미터를 사용하면, SQL 엔진은 (1)그 값이 매칭될 컬럼에 적합한 값인지
, (2)실행될 SQL의 일부로서가 아닌 문자 그대로 처리될 수 있는지
를 확인한다.
단, 개발언어마다 SQL문에 SQ 파라미터를 표시하는 방식이 상이할 수 있다.
# PHP 예시
$stmt = $dbh->prepare("INSERT INTO Customers (CustomerName,Address,City)
VALUES (:nam, :add, :cit)");
$stmt->bindParam(':nam', $txtNam);
$stmt->bindParam(':add', $txtAdd);
$stmt->bindParam(':cit', $txtCit);
$stmt->execute();
출처