SQL 인젝션은 악의적인 사용자가 애플리케이션의 입력 필드를 통해 SQL 코드를 조작하거나 삽입할 수 있는 보안 취약점이다. 이 삽입은 무단 SQL 명령을 실행하거나 데이터베이스 데이터를 변경할 수 있다. SQL 인젝션 공격은 SQL 데이터베이스를 사용하는 웹 애플리케이션에 대한 가장 일반적인 공격 형태 중 하나이다.
출처: https://owasp.org/www-project-top-ten/
OWASP TOP 10에 의하면 2017-2021사이 가장 많이 발생한 웹 애플리케이션 취약점은 SQL Injection이므로 애플리케이션 보안에 기초라고 할 수 있다.
에러 기반 SQL 인젝션은 웹 응용 프로그램의 SQL 쿼리에서 발생하는 오류를 악용하여 데이터베이스의 구조에 관한 정보를 수집하는 공격 유형. 이 기술은 악의적인 SQL 코드를 입력 필드나 매개변수에 삽입하여 응용 프로그램이 데이터베이스에 대해 오류를 생성하도록 유도.
예)
에러 메세지를 토대로 공격자는 새로운 공격 쿼리를 만들 수 있다.
DB 에러 메세지를 노출 시키지 않는다.
SQL Query를 항상 참으로 만들어준다.
예)
select * from members where id = 123 or 1 = 1
기존 쿼리에 공격자가 원하는 UNION 구문 재조합하여 실행
예)
select * from members id = 123 and 1 = 2 UNION select 1, 2, 3, 4 from tables
여기서 UNION 뒤에 있는 쿼리는 공격자가 원하는 정보이다. and 1 = 2로 인해 앞 쿼리는 출력되지 않고 공격자가 원하는 쿼리만 출력된다.
sql에서 제공하는 프로그래밍 기능을 악용하여 정보를 조회한다.
예)
select * from members id = 123 ; exec xp_cmdshell 'cmd.exe /c dir'
이 구문 입력하면 c 드라이브에서 파일 탐색기가 열린다.
Blind SQL Injection은 참(True)인 쿼리문과 거짓(False)인 쿼리문 입력 시 반환되는 서버의 응답이 다른 것을 이용하여 이를 비교하여 데이터를 추출하는 공격이다. Blind SQL Injection은 다른 유형의 SQL Injection과 달리 추출하려는 실제 데이터가 눈에 보이지 않는다. 따라서 참 또는 거짓의 입력값에 따른 서버의 응답을 통해 값을 유추해야 한다.
취약한 예)
<!-- 로그인 폼 -->
<form action="login.php" method="post">
<input type="text" name="username" placeholder="사용자명">
<input type="password" name="password" placeholder="비밀번호">
<button type="submit">로그인</button>
</form>
<?php
// 사용자가 제출한 로그인 폼에서 전달된 데이터 받기
$username = $_POST['username'];
$password = $_POST['password'];
// SQL 쿼리 생성 및 실행
//외부 입력값에 쿼리 조작 문자열 포함 여부를 확인하지 않고 문자열 결합 방식의 쿼리문 생성하고 있다.
$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
$result = mysqli_query($connection, $query);
// 결과 처리
?>
username: ' OR '1'='1
password: ' OR '1'='1
입력값에 쿼리 조작 문자열 포함 여부를 확인하고 사용
오류 처리
제거하고 사용
안전한 형태로 변경해서 사용
PreparedStatement(Query Parameters)와 같은 구조화된 쿼리 실행(파라미터화된 쿼리 실행)을 보장하는 것을 사용
오류 메시지에 상세한 내용(데이터베이스 및 쿼리 구조, 쿼리 실행과 관련한 프로그램 구조 등)이 포함되지 않도록 처리
어플리케이션에서 사용하는 DB 사용자의 권한을 필요한 만큼의 최소한으로 부여
<?php
// 사용자가 제출한 로그인 폼에서 전달된 데이터 받기
$username = $_POST['username'];
$password = $_POST['password'];
// 매개변수화된 쿼리 생성 및 실행
//변수 부분을 ?로 표시 (데이터 타입을 고려하지 않음 = 따움표를 포함하지 않음)
$query = "SELECT * FROM users WHERE username=? AND password=?";
//PreparedStatement 객체를 이용해서 미리 정의한 구조로 쿼리가 실해되는 것을 보장
//구조화된 쿼리 실행 또는 파라미터화된 쿼리 실행
$stmt = mysqli_prepare($connection, $query);
mysqli_stmt_bind_param($stmt, "ss", $username, $password);
mysqli_stmt_execute($stmt);
// 결과 처리
?>
이제 차근차근 String SQL Injection, Numberic SQL Injection, Blind SQL Injection, Blind String SQL Injection, UNION Based SQL Injection, Command Injection에 대해 알아보자