syurhia 님의 블로그
SQL injection을 예방해보자 본문
코드1
<?php
$id = $_GET['id']; // 1. 유저의 입력값을 받는다.
$query = "SELECT * FROM users WHERE id = '" . $id . "'"; // 2. 문자열을 그냥 이어 붙인다. (★치명적 구멍)
$result = mysqli_query($conn, $query); // 3. 오염된 쿼리를 실행한다.
?>
코드1이 가장 간략하게 sql 인젝션이 발생하는 PHP코드이다.
mysqli_query함수는 작성된 쿼리를 바로 실행해주는 함수이다. 이 때, id라는 변수에 통상적인 id값이 아닌 쿼리를 임의로 넣어주면 SQL인젝션이 발생하는 것이다.
이 경우에는 id에 들어올 값들을 직접 체크해서 쿼리가 들어가지 않도록 해야하지만(블랙리스트같이), 블랙리스트와 같은 방법을 도입하면 인코딩을 하는 식으로 우회하는 방법을 통해 SQL인젝션이 발생하게 된다.
가장 좋은 방법으로는 PDO 객체 방식을 이용해서 prepare라는 함수를 통해 쿼리의 뼈대 내용을 정해놓고, id와 같은 부분적인 값은 문자열로만 취급되게 하는 방법이다.
코드2가 그 예시가 된다.
코드2
<?php
// 1. 쿼리의 '틀(뼈대)'을 먼저 만듭니다. 값 자리에는 :id 라는 이름표만 붙여둡니다.
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
// 2. 입력값을 이름표(:id)에 안전하게 바인딩(매핑)하여 실행합니다.
$stmt->execute(['id' => $id]);
// 3. 결과를 가져옵니다.
$user = $stmt->fetch();
?>
이렇게 안전한 방식을 'Prepared Statement'이라고 부른다.
가장 완벽한 방식이라고 불린다고 한다.
다만, 테이블명(예를 들면 코드 2에서의 users 테이블)을 나중에 입력받을 경우에는 Prepared Statement를 쓰지 못한다.(테이블 명까지 전부 작성한 걸 하나의 뼈대로서 이해하기 때문이라는데... 내부 코드까지 보진 못해서 상세하게는 모르겠다.)
또한, ORDER BY같은 정렬을 할 때 정렬 기준 또한 미리 정해줘야 한다는 문제점이 있어서 정렬 기준을 입력값으로써 유저에게 받을 때에는 Prepared Statement를 쓰지 못 한다고 한다.
'보안관련 > PortSwigger' 카테고리의 다른 글
| 2. File path traversal,traversal sequences blocked with absolute path bypass (0) | 2026.05.29 |
|---|---|
| 1. File path traversal, simple case (0) | 2026.05.29 |
| Second-order SQL injection (0) | 2026.05.07 |
| SQL injection with filter bypass via XML encoding (0) | 2026.05.07 |
| Out-of-band (OAST) (0) | 2026.05.06 |