만족
[PHP] Magic Quote는 정말 SQL Injection을 완벽 방어할까? 본문
[PHP] Magic Quote는 정말 SQL Injection을 완벽 방어할까?
Backend/PHP Satisfaction 2020. 10. 26. 01:35SQL Injection이란?
SQL 주입(삽입)이라고도 부르며, 개발자의 의도대로 동작하지 않는 구문을 추가하여 피해를 입히는 공격 방식이다.
SQL Injection 예시
const removeAccount= (accountId)=>{
database.executeQuery(`DELETE FROM Account WHERE id='${accountId}'`);
};
다음과 같은 코드가 있다고 해 보자.
유저가 정상적인 id를 입력할 때는 상관 없지만,
공격자가 accountId 값에
1' OR 1=1; --
를 입력하게 되면 쿼리문은 다음과 같이 변한다.
DELETE FROM Account WHERE id='1' OR 1=1;
따라서 모든 계정이 삭제되는 결과가 초래된다.
이런 식으로 데이터를 몽땅 날려버리거나,
유저 정보를 조회하는 쿼리에 이 공격을 받으면 모든 유저 정보를 탈취할 수도 있다.
www.bloter.net/archives/280164
매우 흔한 공격임과 동시에 상당한 파괴력도 지니고 있기 때문에, 반드시 막아주어야 한다.
먼저 흔한 오해를 바로잡고 가보자.
PHP에선 Magic Quote가 있기 때문에 신경쓰지 않아도 된다?
Magic Quote는 따옴표 속에서 스트링 결합 시 스트링 변수를 자동으로 이스케이핑해 합쳐주는 기능이다.
(addslashes()와 동일하게 동작한다)
$accountId= "my'id";
$query= "DELETE FROM Account WHERE id='$accountId'";
//따옴표 속 $accoundId는 이스케이핑되어 my\'id가 된다.
//최종적으로 $query는 DELETE FROM Account WHERE id='my\'id';가 된다
결론부터 말하자면 틀렸다.
아래의 포스트를 확인해보시라.
짧게 요약하자면,
[어떤 특수한 문자]' (예: %aa')
의 경우 따옴표가 \'로 이스케이핑 되고 문자열 인코딩을 하는 과정에서 앞의 특수한 문자와 \가 하나로 합쳐져
따옴표가 이스케이핑되지 않는 상황이 발생한다는 것이다.
따라서 Magic Quote든, addslashes던 공격자에게 조금의 귀찮음을 유발할 뿐, 실질적인 방어 대책이 되지는 못한다는 뜻이다.
결국은 동적 SQL 구성을 막아야만 한다
유일한 해결법은 PreparedStatement를 통해 미리 SQL을 구조화시켜 동적 SQL 구성을 막아버리는 것이다.
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// prepare and bind
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);
// set parameters and execute
// 첫 번쨰 쿼리 실행
$firstname = "John";
$lastname = "Doe";
$email = "john@example.com";
$stmt->execute();
// 두 번쨰 쿼리 실행
$firstname = "Mary";
$lastname = "Moe";
$email = "mary@example.com";
$stmt->execute();
// 세 번쨰 쿼리 실행
$firstname = "Julie";
$lastname = "Dooley";
$email = "julie@example.com";
$stmt->execute();
echo "New records created successfully";
// 끝!
$stmt->close();
$conn->close();
?>
preparedStatement를 이용한 쿼리 실행은
prepare 시 쿼리를 미리 컴파일하고
bind/execute할 때 컴파일된 쿼리를 사용하기 때문에
동일한 쿼리 템플릿을 사용할 경우, 사용하지 않을 때보다 월등한 속도의 이점도 있다.
이제 statement는 가급적 지양하는 편이 좋겠다.
'Backend > PHP' 카테고리의 다른 글
[PHP] 아이피 정보 조회 및 해외 아이피 차단 (0) | 2022.01.13 |
---|---|
[PHP] 텔레그램 봇 API로 서버 주요 알림 받아보기 (0) | 2021.11.06 |
[PHP] CPU/메모리/디스크 사용량 로드하기 (0) | 2021.04.25 |
[PHP] 즉시 실행 가능한 웹 코드 에디터 (0) | 2020.10.25 |