PHP SQL 인젝션 공격 방어

유지/보수를 진행하던 사이트 10곳가량 인젝션 공격이 동시다발적으로 들어왔다. Apache 로그를 확인해보니 상대는 GET, POST, SERVER 값 등등 모든 값을 수정해서 인젝션 쿼리를 실행했다.


1. 문제 분석

상대의 공격 방법은 union으로 정상적인 쿼리에 자신이 실행하고자 하는 쿼리를 덧붙여 실행하고 sleep으로 실행한 쿼리의 sleep 되는 시간을 통해 값이 참인지 거짓인지 알아내는 방식이었다.
DB 구조, 테이블 이름, 데이터 모두 알아낼 수 있는 위험한 방식이다.

2. 코드 작성 및 적용

다음과 같이 모든 서버에 들어오는 값에서 상대가 실행하는 쿼리의 중요 단어만 제외하는 방법으로 코드를 작성해 적용한다.

<?php
    function hack_check($var){
    $danger_str = array("union", "sleep"); // 이곳에 제외할 단어 작성
    if(is_array($var)){
    $var = array_map("hack_check", $var);
    }else{
    for($i=0; $i<count($danger_str); $i++){
    $var = str_ireplace($danger_str[$i], "", $var);
    }
    }
    return $var;
    }

    if(is_array($_POST)) $_POST = array_map("hack_check", $_POST);
    if(is_array($_GET)) $_GET = array_map("hack_check", $_GET);
    if(is_array($_REQUEST)) $_REQUEST = array_map("hack_check", $_REQUEST);
    if(is_array($_COOKIE)) $_COOKIE = array_map("hack_check", $_COOKIE);
    if(is_array($_SESSION)) $_SESSION = array_map("hack_check", $_SESSION);
    if(is_array($_SERVER)) $_SERVER = array_map("hack_check", $_SERVER);
?>

array_map을 사용해서 서버에 들어오는 모든 값에 특정 단어가 포함되어있는지 검사하고 포함되어 있으면 str_ireplace를 사용해서 포함된 특정 단어들을 제거하는 함수이다. 값에 배열이 담겨있으면 끝까지 배열을 요소 하나로 쪼개서 검사하고 단어를 제거한다.

config나 common 파일 같이 모든 페이지가 불러오는 최상단 파일에 위와 같은 코드를 추가한다.
코드를 적용한 후 일주일간 로그를 확인해보니 상대의 인젝션 공격은 완벽히 차단되었다.

array_map($callback, array $array, array ...$arrays);
배열의 각 요소에 지정한 function을 실행하고 그 결과를 return 한다.

str_ireplace(array|string $search, array|string $replace, string|array $subject, int &$count = null);
문자열을 대소문자 구분 없이 치환 문자열로 변경한다.


위로 스크롤