'SQL 인젝션'에 해당되는 글 1건

728x90
SQL Injection

설명

웹 애플리케이션에서 사용되는 SQL 구문에 공격자가 임의의 구문을 주입(Injection) 하여 내부 데이터베이스의 데이터를 유출, 변조할 수 있는 취약점이다.

 발생원인

웹 페이지에서 사용자로부터 입력받은 값을 제대로 검사하지 않고 그대로 데이터 질의어로 사용할 경우 발생한다.

 위험성

데이터 유출, 변조 외에도 서버에 파일을 쓰거나 읽을 수 있고, 직접 명령 실행도 가능할 수 있기 때문에 위험도가 높은 취약점이다.


SQL 인젝션은 데이터베이스를 사용하는 모든 언어에서 일어날 수 있다.
공격자는 SQL 인젝션 취약점을 사용하여 데이터베이스 내의 모든 정보를 추출할 수 있다.
보통 userID 와 passwd 를 입력하는 로그인 창에서 발생할 수 있는 공격 유형이다.


select * from members where userID='$userID' and passwd ='$passwd';

여기서 userID 에 입력하는 정보를 ' or 1=1-- 라고 입력하는 것이 받아들여지면 어떤 결과가 초래될까?
phpMyAdmin 상에서 직접 테스트 해보라.


SELECT * FROM members WHERE userID='' or 1=1 --' and passwd ='abc123';

과같이 -- 주석 뒷부분은 무용지물이 되고 조건문은 무조건 참이 되어 모든 결과를 반환하게 된다.


select * from members where userID='a' and passwd ='password' OR 1='1';
로 입력해도 무조건 참이 되어 모든 결과를 반환하게 된다.


더 위험한 것은 테이블 자체를 삭제시켜 버릴 수가 있다는 점이다.

SELECT * FROM members WHERE userID = 'a';DROP TABLE members;

$userID = "admin";
$password = "password' OR 1='1 --";
$sql = "SELECT * FROM members WHERE userID='{$userID}' AND passwd='{$password}'";
echo 'NonFiltering : '.$sql.'<br/>';
$sql=preg_replace("/\s{1,}1\=(.*)+/","",$sql); // 공백이후 1=1이 있을 경우 제거
$sql=preg_replace("/\-{2,}/","",$sql); // 주석 제거
$sql=preg_replace("/\s{1,}(or|and|null|where|limit)/i"," ",$sql); // 공백이후 or, and 등이 있을 경우 제거
echo 'Filtering : '.$sql.'<br/>'; 

공백이후 and 를 체크하지 않고 그냥 체크하면 userID 중에 hand 가 들어간 것도 필터링을 해서 문제가 될 수 있다.


그럼 여기서 안전하게 코딩하기 위한 포인트는 무엇인가?

① 필터링 메소드를 만들어서 악의적인 코드를 무조건 걸러내도록 한다.

    필터링 해야 할 특수문자 : '(홀따옴표) ;(콜론), --(주석), 공백 등

    https://link2me.tistory.com/1489 정규표현식 연습 참조하면 정규표현식 이해에 도움된다.

    정규표현식을 활용한 함수 만들기

    function SQLFiltering($str){
        // 해킹 공격을 대비하기 위한 코드
        $str=preg_replace("/\s{1,}1\=(.*)+/","",$str); // 공백이후 1=1이 있을 경우 제거
        $str=preg_replace("/\s{1,}(or|and|null|where|limit)/i"," ",$str); // 공백이후 or, and 등이 있을 경우 제거
        $str = preg_replace("/[\s\t\'\;\=]+/","", $str); // 공백이나 탭 제거, 특수문자 제거
        return $str;
    }

②  안전한 코딩은 prepared Statement 와 바인딩 변수를 이용하도록 권고하고 있다.

      Prepared Statement 를 쓰면 SQL 인젝션 공격이 불가능할 수 밖에 없다.

      바인딩 데이터는 SQL 문법이 아닌 내부의 인터프리터나 컴파일 언어로 처리하기 때문에

      문법적인 의미를 가질 수 없다.

$stmt = $mysqli->prepare("SELECT * FROM members WHERE userID= ? AND passwd = ?");
$stmt->bind_param("ss", $_POST['userID'], $_POST['passwd']);
$stmt->execute();
//fetching result would go here, but will be covered later
$stmt->close();


참고하면 도움이 될 게시글

ㅇ PHP Prepared Statements https://www.w3schools.com/php/php_mysql_prepared_statements.asp
ㅇ PHP Legacy 함수를 PDO 방식 함수로 변환하기 https://link2me.tistory.com/1636

'Web 프로그램 > Web Security' 카테고리의 다른 글

HTML Purifier 사용법 예시  (0) 2023.02.28
remote IP address  (0) 2021.03.24
파일 다운로드 공격 방지  (0) 2019.07.05
파일 업로드 공격 방지  (0) 2019.06.21
Cross-Site Scripting (XSS) 방지  (0) 2019.06.20
블로그 이미지

Link2Me

,