php 입문 | form 전송 기본 | 보안 대책의 첫 걸음(XSS 방어)

양식을 송신해서 서버에 처리한다는 것은 “서버 측 프로그래밍"의 첫발을 내딛은 당신이 다음에 꼭 해야 하는 것이다. 무엇일까? 그것은 “지금 만든 프로그램의 ‘구멍’ 막는 것"이다.

서버에 프로그램을 제공하는 것은 불특정 다수의 사람이 해당 서버에 액세스하고 그 프로그램이 실행된다는 것이다. 즉, 서버에 액세스하는 모든 사람에게 “그 프로그램이 안전하게 움직인다"라는 것을 보장할 의무가 발생한다는 것이다. 만약에 그 프로그램에 의해 이용자에게 어떠한 피해가 발생하면 그 책임은 만든 개발자에게 있는 것이다.

물론 처음부터 “모든 보안 대책을 세우라"라는 말은 아니다. 하지만 적어도 최소한의 “기본적인 안전 대책"에 대해서는, 프로그램을 만들게되면 가장 먼저 배워야 한다.

그런데 지금 만든 예제 프로그램에는 커다란 ‘구멍’이 뚫려 있다. 그럼 그 구멍을 확인해 보자. 브라우저에서 이전의 페이지로 접근하여 다음과 같이 써보내 보자.

<script>alert("이 구멍이다!");</script>

전송하면 화면에 알림 창이 나타난다(최근의 브라우저에서는 이를 자동으로 막아주고 경고 메세지가 표시한다). 입력 필드에 쓴 JavaScript 스크립트가 페이지를 로드할 때 실행되는데 이런 현상이 일어나고있는 것이다. 왜 이것이 “구멍"인가? 그것은 “어디의 누군지는 모르는 사람이 여기에 JavaScript 스크립트를 작성하여 페이지를 표시했을 때 그것을 실행시켜 버릴 수 있기” 때문이다.

예를 들어, 이런 식으로 게시판 프로그램을 만들었다고 하자. 그러면 거기에 접근한 사람이 지금과 같이 하여 JavaScript 스크립트를 몰래 게시한다. 다음에 이 게시판에 접근한 모든 사람에게 표시가 될 때에 스크립트가 실행된다. 예를 들어 스크립트에서 “브라우저에 저장되어 있는 쿠키 정보를 얻어서 다른 사이트에 보낸다” 것과 같은 처리가 적혀 있었다고 한다면? 액세스한 사람의 쿠키 정보가 모든 낯선 사람에 도난하실 수 있다.

이른바 ‘스푸핑(Spoofing)‘라는 범죄는 이렇게 발생한다. 이 스크립트를 이용한 방법은 “크로스 사이트 스크립팅(XSS)“라고 사이트 공격의 기본 중의 기본으로 널리 알려져 있다.

그럼 이 뚫린 ‘구멍’을 막아 보자. 먼저해야할 보안 대책은 사실 의외로 간단하다. 텍스트를 화면에 표시하는 echo 문 스크립트를 다음과 같이 다시 작성할 뿐이다.

<?php
    echo htmlspecialchars($result);
?>

이 “htmlspecialchars"라는 함수는 ()에 쓰여진 값(인수라고 한다)를 체크하고 HTML 태그를 모두 이스케이프 문자로 변환한 것을 돌려준다. 즉, 이렇게 하여 값을 기록한 것으로, <script> 태그 등을 모두 무효화하고 동작하지 않도록 할 수 있다.

양식을 사용하는 경우에는 보안 대책에 관한 철칙이 있다. 그것은 “사용자로부터 보내져 온 데이터는 절대로 그대로 화면에 출력하지 않는다"는 것이다. 거기에는 어떤 내용이 기술되어 있는지 모르기 때문에, 반드시 “표시해도 괜찮은” 형태로 처리해서 출력하는 것이 양식 사용의 기본이다.

<?php
    $str = $_POST['text1'];
    if ($str != null){
        $result = "당신은 '{$str}'이라고 썼습니다.";
    } else {
        $result = "아무것도 쓴 것이 없습니다.";
    }
?>
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
        <title>sample page</title>
    </head>
    <body>
        <h1>Hello PHP!</h1>
        <div><?php
            echo  htmlspecialchars($result);
        ?></div>
        <form method="post" action="./index.php">
            <input type="text" name="text1">
            <input type="submit">
        </form>
    </body>
</html>



최종 수정 : 2021-08-27