웹사이트의 방문자가 게시판에 글을 작성하면서 글 내용에 자바스크립트 코드를 심어 사이트를 공격해 오는 경우가 있다.
이런 것을 XSS라고 하는데, 이번 포스트에서는 이 공격을 무력화시키는 법을 공부해 보겠다.
이전 포스트
php, 중복된 코드를 리팩토링 (feat. require와 include)
생활코딩의 php 수업 영상: 보안 XSS
XSS (Cross-Site Scripting)란?
XSS는 게시판이나 댓글창처럼 사용자가 글을 남길 수 있는 곳에 악의적인 스크립트(주로 JavaScript)를 삽입하는 공격 방식이다.
생활코딩 수업 영상에서는 귀여운 예를 보여줬지만, 사용자의 쿠키(세션 ID)를 탈취하여 로그인을 가로채거나, 가짜 로그인 페이지로 리다이렉트 시키는 등 심각한 피해를 줄 수 있다.
htmlspecialchars()
htmlspecialchars() 함수는 HTML에서 특수한 의미를 가진 문자들을 브라우저가 코드로 해석하지 못하도록 단순 문자로 변환하는 역할을 한다.
이를 이스케이프Escape라고 부른다.
그렇게 문자열 안의 특수문자들(코드를 쓸 때 사용하는 <, >, &, " 등)을 그냥 보이는 그대로 출력해서 XSS 공격을 무력화시켜 준다.
strip_tags()
위의 생활코딩 수업 영상의 9분 28초에 이고잉 님께서 언급하는 내장 함수다.
모든 태그를 문자로 바꿔버리는 htmlspecialchars()와 달리, 특정 태그(예: <a>, <b> 등)만 허용하고 나머지는 모두 제거하고 싶을 때는 strip_tags() 함수를 사용한다.
<?php
$input = "<h1>제목</h1>
<p>본문입니다.</p>
<script>alert('공격');</script>
<a href='#'>링크</a>";
// 1. 모든 태그 제거
echo strip_tags($input);
// 2. 특정 태그(<a>, <h1>)만 허용
echo strip_tags($input, '<a><h1>');
?>
strip_tags() 함수는 문자열에서 HTML 태그를 모두 제거한다.
htmlspecialchars()는 태그를 문자로 변환해서 보여줬지만, strip_tags()는 태그를 아예 삭제해버린다.
이때 두 번째 인자를 사용하면 제외할(허용할) 태그를 지정할 수 있다.
strip_tags()는 안전할까?
영상 속에서 언급하는 함수라서 어쩔 수 없이 정리는 했지만, 사실 시간낭비 같아서 정리하고 싶지 않았다. 🙄
strip_tags()는 보안상 치명적인 약점이 있다.
바로 태그 안의 속성은 건드리지 않는다는 점이다.
만약 <a> 태그를 허용했다면, 공격자는 다음과 같은 코드를 쓸 수 있다.
<a href="#" onclick="악성코드">클릭하세요</a>
strip_tags()는 <a> 태그 자체는 허용된 것이므로 통과시키지만, 그 안의 onclick 같은 HTML 요소를 클릭했을 때 실행될 자바스크립트 코드를 담는 이벤트 속성까지 걸러내지는 못한다.
onclick 속성은 버튼뿐만 아니라 이미지, 글자 등 거의 모든 태그에 붙여서 동작을 만들 수 있다.
즉, 글쓰기 시 일부 태그(진하게, 밑줄 등)를 허용하고 싶어도 strip_tags()는 좋은 방법이 아니다.
실제 상용 서비스에서 글을 쓸 때 일부 태그를 허용하고 싶다면, php 내장 함수보다는 HTML Purifier 같은 전문 라이브러리를 사용하는 것이 좋다.
다음 포스트
php 보안: 파일 경로 보호 내장 함수 basename으로 Directory Traversal 공격 방어
응원이나 피드백이 담긴 댓글은 제가 계속 블로그를 해나갈 수 있는 원동력이 됩니다. 😊
지인에게 보여주고 싶은 글이었다면 URL을 복사해서 메신저나 소셜 미디어에 공유해 주세요.
0 Comments
댓글 쓰기
🔸 댓글은 블로그 운영자의 승인 후에 블로그에 표시됩니다.
🔸 비로그인 방문자 분께서는 '익명'보다 이름/URL로 댓글을 남겨주시면 감사하겠습니다. (URL은 생략 가능합니다.)
🔸 구글 로그인 방문자는 '알림 사용'에 체크를 하시면, 남겨주신 댓글에 대한 답글 알림을 메일로 받아볼 수 있습니다. 📩