SQL Injection

최건우·2023년 2월 3일
0

데이터베이스/SQL

목록 보기
2/13

SQL Injection

  • SQL injection은 데이터베이스에 피해를 끼칠 수 있는 '코드 주입 기술(code injection technique)'이다.
  • 가장 일반적인 웹 해킹 기술 중 하나이다. 서비스에서 사용자에게 어떠한 input 행위를 요구할 때, 사용자는 입력값을 통해 SQL문을 서버에 제공할 수 있고 이는 서버가 알지 못하는 사이에 DB에서 실행될 수 있다.
  • 필자는 실제로, UPDATE 문에 입력값을 잘못 넣었다가 해당 테이블의 데이터 전체가 입력값대로 바뀌어버리는 경험을 한 적이 있다.

입력을 이용한 공격 유형

1=1이 항상 True라는 점을 이용한 SQL injection

서비스에서 닉네임, 번호 등을 입력하는 아래와 같은 형태의 SQL이 있다고 가정하자.
이 SQL문은 UserId에 따라 한 명의 유저를 조회하기 위한 것으로서, txtSQL은 유저의 입력값에 따라 완성된다.

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

만약 '잘못된 입력값'을 방지할 대책이 세워져 있지 않다면, 유저는 UserId105 OR 1=1 과 같은 값을 의도적으로 입력할 수 있다. 그러면 SQL문은 아래와 같이 되고, 이는 OR 1=1이 항상 참이기 때문에 모든 유저 정보를 가져올 것이다.

SELECT * FROM Users WHERE UserId = 105 OR 1=1;

만약 테이블에 실명, 연락처, 비밀번호 등의 개인정보가 들어잇다면, 심각한 유출 사고가 일어날 것이다.

"="은 항상 True라는 점을 이용한 SQL injection

유저로부터 이름, 패스워드를 입력받아 유저 조회에 사용한다고 가정해 보자.

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를 이용한 SQL injection

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;

그리고 만약 해커가 UserId105; DROP TABLE Suppliers를 입력한다면, 다음과 같이 Batched SQL이 완성되어 연쇄적으로 실행된다.

SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers;

이 공격으로 인해 Suppliers 테이블은 삭제될 것이다.

방어하기: SQL 파라미터 사용하기

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();




출처

profile
부족한 경험을 채우기 위한 나만의 기록 공간

0개의 댓글