SQL 인젝션
프로그램 부 에서 DB 로 질의 하는 QUERY문 을 공격자가 임의로 변조하여 허가되지 않은 자료나 관리자/회원 권한을 획득할 수 있는 공격입니다.
공격 예제
<?php
// 회원 로그인 시 아이디와 패스워드가 맞는 회원정보를 찾는 쿼리
$query = "SELECT * FROM users WHERE user='{$_POST['username']}' AND password='{$_POST['password']}'";
mysql_query($query);
// 회원 로그인 시 아이디와 패스워드가 맞는 회원정보를 찾는 쿼리
$query = "SELECT * FROM users WHERE user='{$_POST['username']}' AND password='{$_POST['password']}'";
mysql_query($query);
// $_POST['password'] 을 체크하지 않은 경우 아래와 같이 공격자의 입력이 있을 수 있음
$_POST['username'] = 'aidan';
$_POST['password'] = "' OR ''='";
$_POST['username'] = 'aidan';
$_POST['password'] = "' OR ''='";
// 쿼리출력
echo $query;
// DB로 전송되는 쿼리를 출력해 보면 아래와 같다.
// SELECT * FROM users WHERE user='aidan' AND password='' OR ''=''
// 이 쿼리는 ''='' 조건이 or 로 조합되어 있어 무조건 참이며 DB는 aidan 이라는 회원의 레코드셋을 반환하게 된다.
?>
echo $query;
// DB로 전송되는 쿼리를 출력해 보면 아래와 같다.
// SELECT * FROM users WHERE user='aidan' AND password='' OR ''=''
// 이 쿼리는 ''='' 조건이 or 로 조합되어 있어 무조건 참이며 DB는 aidan 이라는 회원의 레코드셋을 반환하게 된다.
?>
해결책
가변적으로 대입되는 쿼리문의 모든 요소를 mysql_real_escape_string() 이라는 함수를 이용하여 특수 문자를 escape 시켜야 합니다. 아래의 예제는 php.net 에서 권장하는 가장 좋은 방법의 예 입니다.
<?php
if (isset($_POST['product_name']) && isset($_POST['product_description']) && isset($_POST['user_id'])) {
// 접속
$link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password');
if (isset($_POST['product_name']) && isset($_POST['product_description']) && isset($_POST['user_id'])) {
// 접속
$link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password');
if(!is_resource($link)) {
echo "서버 접속 실패n";
// ... 오류를 적절히 기록
// ... 오류를 적절히 기록
} else {
// ON일 경우 magic_quotes_gpc/magic_quotes_sybase 효과 제거
if(get_magic_quotes_gpc()) {
$product_name = stripslashes($_POST['product_name']);
$product_description = stripslashes($_POST['product_description']);
} else {
$product_name = $_POST['product_name'];
$product_description = $_POST['product_description'];
}
$product_name = stripslashes($_POST['product_name']);
$product_description = stripslashes($_POST['product_description']);
} else {
$product_name = $_POST['product_name'];
$product_description = $_POST['product_description'];
}
// 안전한 질의 만들기
$query = sprintf("INSERT INTO products (`name`, `description`, `user_id`) VALUES ('%s', '%s', %d)",
mysql_real_escape_string($product_name, $link),
mysql_real_escape_string($product_description, $link),
$_POST['user_id']);
$query = sprintf("INSERT INTO products (`name`, `description`, `user_id`) VALUES ('%s', '%s', %d)",
mysql_real_escape_string($product_name, $link),
mysql_real_escape_string($product_description, $link),
$_POST['user_id']);
mysql_query($query, $link);
if (mysql_affected_rows($link) > 0) {
echo "Product insertedn";
}
}
} else {
echo "Fill the form propertyn";
}
?>
echo "Product insertedn";
}
}
} else {
echo "Fill the form propertyn";
}
?>
보통, 기본적으로 Magic Quotes 설정에 의해 막아지고는 있으나 6.0 이상부터는 이 기능이 제거되니 의존하지 않기를 권장하고 있습니다.
에이빌더에서는 library_lite.class.php 내의 함수 sql_inj_get_safe_value, sql_inj_get_query 로 조치하고 있으며 지속으로 패턴을 추가하고 있습니다.












