[PHP] 보안 - XSS(Cross Site Scripting) & CSRF

Seo Joonsoo·2022년 6월 21일
0

php

목록 보기
16/23

서론

모든 값을 다룰 때는 해당 데이터가 오염되었다는 가정하에 사용하는 것이 좋습니다.
클라이언트로 부터 받아오는 값을 서버에서는 필터를 통한 다음 사용하여야 하며,
클라이언트로 전달할 값 또한 필터를 거친 다음 출력하여야 합니다.

웹 개발은 사실 어떤 것 보다 가장 쉬우면서도 어려운게 이러한 부분들이 아닌가 싶습니다.
값 하나를 출력하거나 입력 받을 때도 수많은 경우를 고려하여야만이 비로소 견고한 웹이 제작되기 때문입니다.

보안은 습관임과 동시의 시스템이라 생각합니다. 어떤 제작사든 이에 대한 올바른 가이드라인을 제작하여 이를 바탕으로 수행하는 것이 좋습니다. 회사는 개개인의 역량을 통해 하나의 시스템을 만드는 곳이기 때문입니다.

서두가 길었습니다. 이번 편은 보안에 대한 이야기로 그중에서도 XSS에 대한 가벼운 글 입니다.

누군가 이 글을 읽는 다면 혹시나 저와 같은 루키시라면 백앤드를 지향하시더라도 프론트에 대한 전반적인 워크플로우를 이해하고 숙지하신다면 필히 좋은 정상을 향해 나아갈 수 있을 것 입니다.

XSS란?

XSS는 Cross-Site Scripting의 약자로 CSS가 되어야 함이 옳지만 CSS는 이미 Cascading Style Sheets라는 뜻으로 정의되어 있어 선이 겹치는 X를 차용해 XSS가 되었습니다.

XSS 공격은 웹 애플리케이션이 사용자로부터 입력 받은 값을 제대로 검사하지 않고 사용할 때 유효한 공격입니다.

주로 여러 사용자들이 보게되는 게시판에 악성 스크립트를 내포하여 글을 올리곤 합니다. 이러한 공격을 통해 서버에는 악성 스크립트가 포함된 정보가 저장되게 되고 이렇게 저장된 스크립트는 서버를 통해 또다시 출력되게 됩니다.

이렇듯 XSS는 사용자로부터 값을 받아와 출력하는 모든 곳에 사용될 수 있습니다.
※ XSS공격을 막기 위해 클라이언트 단에서 검사하지 마십시오. 해당 필터를 우회할 수 있으므로 클라이언트 사이드 필터 유무와 관계 없이 서버에서도 검사하여야 합니다.

이를 활용한 공격은 CSRF(XSRF)로 발전될 수 잇습니다. CSRF에 대한 내용은 본고에 담지않습니다.
XSS공격은 결국 서버에서 클라이언트에 대한 악성 공격을 수행하게 됩니다.

htmlentities($_POST['content']);
strip_tags($_POST['content']);
filter_input(INPUT_POST, 'content', FILTER_SANITIZE_FULL_SPECIAL_CHARS);

output_add_rewrite_var('csrf_token', $_SESSION['token']);

예 #1. token을 사용한 CSRF 공격 보안

session_start();

switch($_SERVER['REQUEST_METHOD']) {
    case 'GET':
        $_SESSION['token'] = bin2hex(random_bytes(32));
        output_add_rewrite_var('csrf_token', $_SESSION['token']);

        echo <<< 'HTML'
<form action="/" method="POST">
    <textarea name="content" rows=25 cols=50> </textarea>
    <input type="submit">
</form>
HTML;
        break;
    case 'POST':
        if (hash_equals($_SESSION['token'], $_POST['csrf_token'])) {
            $uid = $_POST['uid'];
            echo 'Hello, world';
        }

        // echo htmlentities($_POST['content']).PHP_EOL;
        // echo strip_tags($_POST['content']).PHP_EOL;
        echo filter_input(INPUT_POST, 'content', FILTER_SANITIZE_FULL_SPECIAL_CHARS).PHP_EOL;
        break;
    default:
        http_response_code(404);
}

32byte의 난수를 생성하여 세션에 저장하고 해당 값을 클라이언트 FORM에 hidden으로 출력합니다. 이렇게 전송된 토큰 값을 submit될 때 받아와 비교하게 된다면 session에 저장된 토큰과 클라이언트로부터 받아온 토큰값을 비교하여 검증할 수 있습니다.

일반적으로 이러한 값을 nonce라고 합니다. 프레임워크나 Wordpress와 같은 CMS에서는 이와 관련된 함수들은 nonce와 같은 이름으로 붙여져 있으므로 참고하여 주시기 바랍니다.

이렇듯 XSS 공격은 값을 서버로 받아올 때와 서버에서 내보낼 때 모두 해주셔야 합니다.

profile
여러분들 삶에 한 획을 더하고 싶습니다.

1개의 댓글

comment-user-thumbnail
2022년 12월 17일

보안의 중요성에 대해 다시한번 생각하는 계기가 되었습니다 너무 감사합니다!

답글 달기