Injection
SQL Injection은 데이터베이스를 파괴할 수 있는 코드 주입 기술이다.
SQL Injection은 가장 일반적인 웹 해킹 기술 중 하나이다.
SQL Injection은 웹 페이지 입력을 통해 SQL 문에 악성 코드를 배치하는 것이다.
SQL Injection은 일반적으로 사용자에게 사용자 이름/사용자 ID와 같은 입력을 요청하고 이름/ID 대신 사용자가 데이터베이스에서 무의식적 으로 실행할 SQL문을 제공할 때 발생한다.
예시
SELECT 문자열에 변수(txtUserId)를 추가하여 문장 을 생성
txtUserId = getRequestString("UserId"); txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
변수는 사용자 입력(getRequestString)에서 가져온다.
잠재적인 위험
1=1을 기반으로 하는 SQL Injection은 항상 참이다.
위의 예시를 다시 참고하자.
코드의 원래 목적은 주어진 사용자 ID로 사용자를 선택하는 SQL 문을 만드는 것이었다.
사용자가 “wrong” 입력을 입력하는 것을 방지할 방법이 없다면 사용자는 다음과 같이 “smart” 입력을 입력할 수 있다.
UserId:
위와 같이 입력시 표시되는 SQL 문
SELECT * FROM Users WHERE UserId = 105 OR 1=1;
위의 SQL은 유효하며 OR 1=1 이 항상 TRUE 이기 때문에 “Users” 테이블의 모든 행을 반환한다.
“Users” 테이블에 이름과 암호가 포함되어 있으면 어떻게될까?
위 문과 동일한 SQL 문
SELECT UserId, Name, Password FROM Users WHERE UserId = 105 or 1=1;
해커는 단순히 105 OR 1=1을 입력 필드에 삽입하여 데이터베이스의 모든 사용자 이름과 암호에 액세스할 수 있다.
“”=””에 기반한 SQL Injection은 항상 참이다.
예시
다음은 웹 사이트에서 사용자 로그인의 예시이다.
사용자 이름:
비밀번호:
입력한 값을 DATABASE에 저장한다.
uName = getRequestString("username"); uPass = getRequestString("userpassword");
SQL 결과
SELECT * FROM Users WHERE Name ="John Doe" AND Pass ="myPass"
해커는 사용자 이름 또는 암호 텍스트 상자에 ” OR “”=”를 삽입하기만 하면 데이터베이스의 사용자 이름과 암호에 액세스할 수 있다.
사용자 이름:
비밀번호:
SQL 결과
SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""
위의 SQL은 유효하며 OR “”=”” 가 항상 TRUE 이기 때문에 “Users” 테이블의 모든 행을 반환한다.
Batched SQL 기반
대부분의 데이터베이스는 Batched SQL 문을 지원한다.
SQL 문의 일괄 처리는 세미콜론으로 구분된 둘 이상의 SQL 문의 그룹이다.
“Users” 테이블의 모든 행을 반환한 다음 “Suppliers” 테이블을 삭제
SELECT * FROM Users; DROP TABLE Suppliers
예시
txtUserId = getRequestString("UserId"); txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
해커가 사용자 이름 필드에 아래와 같이 입력
사용자 ID:
SQL 결과
SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers;
보호를 위해 SQL 매개변수 사용
SQL Injection으로부터 웹 사이트를 보호하기 위해 SQL 매개변수를 사용할 수 있다.
SQL 매개변수는 실행 시 제어된 방식으로 SQL 쿼리에 추가되는 값이다.
ASP.NET Razor 예시
txtUserId = getRequestString("UserId"); txtSQL = "SELECT * FROM Users WHERE UserId = @0"; db.Execute(txtSQL,txtUserId);
매개변수는 SQL 문에서 @ 마커로 표시됩니다.
SQL 엔진은 각 매개변수가 해당 열에 대해 올바른지 확인하고 실행할 SQL의 일부가 아닌 문자 그대로 처리되는지 확인합니다.
또 다른 예시
txtNam = getRequestString("CustomerName"); txtAdd = getRequestString("Address"); txtCit = getRequestString("City"); txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)"; db.Execute(txtSQL,txtNam,txtAdd,txtCit);
예시
다음 예에서는 일부 일반적인 웹 언어로 매개변수화된 쿼리를 작성하는 방법을 보여준다.
ASP.NET의 SELECT 문
txtUserId = getRequestString("UserId"); sql = "SELECT * FROM Customers WHERE CustomerId = @0"; command = new SqlCommand(sql); command.Parameters.AddWithValue("@0",txtUserId); command.ExecuteReader();
ASP.NET의 문에 삽입
txtNam = getRequestString("CustomerName"); txtAdd = getRequestString("Address"); txtCit = getRequestString("City"); txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)"; command = new SqlCommand(txtSQL); command.Parameters.AddWithValue("@0",txtNam); command.Parameters.AddWithValue("@1",txtAdd); command.Parameters.AddWithValue("@2",txtCit); command.ExecuteNonQuery();
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();