PHP mysql에서 SQL 인젝션 공격은 무엇이고 어떻게 막을 수 있나요?
PHP mysql에서 SQL 인젝션 공격은 무엇이고 어떻게 막을 수 있나요?
SQL 인젝선은 공격자가 악의적인 SQL 선언을 만들어 데이터베이스 서버를 조작할 수 있는 공격을 의미해요.
SQL 인젝션은 가장 흔하고 가장 위험한 웹 어플리케이션 취약점 중 하나에요.
SQL 인젝션 공격을 막기 위해서는 어떻게 SQL 인젝션을 하는지 알아야겠죠.
웹 어플리케이션이 사용자의 입력 값을 SQL 선언에 바로 포함시키는 경우 SQL 인젝션 공격이 일어날 수 있어요.
예를 들어 다음의 코드를 보세요:
$username = $_POST["username"];
$password = $_POST["password"];
$mysqli->query("SELECT * FROM users WHERE username='{$username}' AND password='{$password}'");
위의 코드는 사용자로부터 아이디와 비밀번호를 입력받아서 일치하는 행을 선택하고 있어요.
그런데 위의 코드는 공격자가 악의적인 입력 값을 제출할 수 있기 때문에 SQL 인젝션으로부터 취악해요.
예를들어 공격자가 유저네임에 admin, 패스워드에 password' OR 1=1 -- 을 입력하면 이렇게 되겠죠:
SELECT id FROM users WHERE username='admin' and password='password' OR 1=1 --'
이 방법으로 비밀번호를 입력하지 않고 로그인 할 수 있어요.
공격자가 인증을 건너뛸 수 있어요.
공격자가 데이터를 수정하거나 삭제할 수 있어요. 심지어 테이블 전체를 삭제하는것도 가능하죠.
공격자가 특정 데이터를 조회하거나 심지어 완전히 데이터베이스 전체를 빼낼 수도 있어요.
만약 데이터베이스 서버가 운영 체제의 명령을 실행할 수 있도록 만들어진 경우 그것보다 더 나쁜 일이 일어날 수도 있어요.
SQL 인젝션이 위험하다는 것은 알았으니 이제 어떻게 방어하는지 알아야겠죠.
SQL 인젝션을 방어하기 위해 가장 좋은 방법은 prepared statement (준비된 선언) 를 사용하는 방법이에요.
PDO 또는 MySQLi 중 하나로 준비된 선언을 사용할 수 있어요. 두 개의 차이점에 대해서는 MySQLi와 PDO 중 어떤걸 쓰는게 좋나요? 질문을 참고하세요.
// PDO 방법
$username = $_POST["username"];
$password = $_POST["password"];
$pdo = new PDO('mysql:dbname=testdb;host=127.0.0.1', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$st = $pdo->prepare('SELECT * FROM users WHERE username=:username AND password=:password');
$st->bindParam(':username', $username);
$st->bindParam(':password', $password);
$st->execute();
var_dump($st->fetchObject());
// MySQLi 방법
$username = $_POST["username"];
$password = $_POST["password"];
$mysqli = new mysqli('localhost', 'username', 'password', 'testdb');
$st = $mysqli->prepare('SELECT * FROM users WHERE username=? AND password=?');
$st->bind_param('s', $username);
$st->bind_param('s', $password);
$st->execute();
$result = $st->get_result();
var_dump($result->fetch_object());
이 방법 보다는 준비된 선언을 더 추천해요.
그래도 정말 정말 이스케이프를 사용하고 싶다면 여기에 mysqli_real_escape_string 함수를 사용하는 방법이 있어요.
$username = $mysqli->real_escape_string($_POST["username"]);
$password = $mysqli->real_escape_string($_POST["password"]);
$mysqli->query("SELECT * FROM users WHERE username='{$username}' AND password='{$password}'");