이전 글에서 SQL Injection에 대해 정리하면서, 사용자 입력값을 안전하게 처리하지 않으면 보안 취약점으로 이어질 수 있다는 점을 알게 되었다.
웹 보안에서 SQL Injection과 함께 자주 등장하는 공격 중 하나가 XSS이다. SQL Injection이 데이터베이스에 영향을 주는 공격이라면, XSS는 사용자의 브라우저에서 악성 스크립트가 실행될 수 있다는 점에서 차이가 있다.
이번 글에서는 XSS가 무엇인지, 왜 발생하는지, 어떤 피해로 이어질 수 있는지, 그리고 어떻게 방어할 수 있는지 정리해보려고 한다.
XSS는 Cross-Site Scripting의 약자로, 웹 페이지에 악성 스크립트를 삽입해 다른 사용자의 브라우저에서 실행되도록 만드는 공격이다.
게시글, 댓글, 검색창처럼 사용자가 입력한 내용이 다시 웹 페이지에 출력되는 기능은 많은 웹 서비스에서 사용된다. 이때 입력값이 안전하게 처리되지 않으면, 브라우저는 입력값을 단순한 텍스트가 아니라 실행 가능한 스크립트로 해석할 수 있다.
즉, XSS의 핵심은 사용자 입력값이 브라우저에서 실행 가능한 코드로 해석되는 문제라고 볼 수 있다.
XSS는 사용자의 입력값을 검증하거나 안전하게 변환하지 않은 채 웹 페이지에 출력할 때 발생할 수 있다.
대표적인 발생 원인은 다음과 같다.
결국 XSS는 웹 애플리케이션이 사용자 입력값을 안전한 텍스트로 처리하지 못할 때 발생하는 취약점이다.
예를 들어 댓글 기능이 있는 웹 페이지를 생각해보자.
사용자가 다음과 같이 댓글을 입력하면,
안녕하세요!
화면에는 단순한 텍스트로 표시된다.
하지만 공격자가 다음과 같은 값을 입력하고, 서버가 이를 그대로 출력한다면 문제가 발생할 수 있다.
<script>alert('XSS')</script>
이 값이 안전하게 처리되지 않고 HTML 문서에 포함되면, 브라우저는 이를 단순한 글자가 아니라 실행 가능한 스크립트로 해석할 수 있다.
예를 들어 HTML에는 다음과 같은 형태로 포함될 수 있다.
<p><script>alert('XSS')</script></p>
이 경우 브라우저는 <script> 태그를 코드로 해석하고 실행할 수 있다.
또 다른 예로 이미지 태그의 이벤트 속성을 악용하는 방식도 있다.
<img src="x" onerror="alert('XSS')">
중요한 점은 특정 공격 코드를 외우는 것이 아니다.
핵심은 사용자 입력값이 HTML 문서 안에서 코드로 해석될 수 있다는 점이다.
XSS가 발생하면 다음과 같은 피해로 이어질 수 있다.
즉, XSS는 서버 자체보다 사용자의 브라우저와 세션을 노리는 공격에 가깝다.
XSS는 발생 방식에 따라 크게 세 가지로 나눌 수 있다.
Stored XSS는 악성 스크립트가 서버에 저장된 뒤, 다른 사용자가 해당 페이지를 볼 때 실행되는 방식이다.
예를 들어 공격자가 게시글이나 댓글에 악성 스크립트를 저장하면, 이후 해당 글을 보는 사용자들에게 스크립트가 실행될 수 있다.
Stored XSS는 한 번 저장되면 여러 사용자에게 영향을 줄 수 있기 때문에 위험도가 큰 편이다.
Reflected XSS는 사용자의 요청에 포함된 입력값이 서버 응답에 바로 반영되면서 발생하는 방식이다.
예를 들어 검색어가 화면에 그대로 출력되는 기능에서 입력값을 제대로 처리하지 않으면, 조작된 링크를 통해 스크립트가 실행될 수 있다.
Reflected XSS는 보통 사용자가 특정 링크를 클릭하도록 유도하는 방식과 함께 사용될 수 있다.
DOM-based XSS는 브라우저에서 실행되는 JavaScript 코드가 DOM을 조작하는 과정에서 발생한다.
서버 응답보다 클라이언트 측 코드에서 입력값을 안전하게 처리하지 못할 때 발생할 수 있다.
XSS를 방어하기 위해서는 사용자의 입력값이 브라우저에서 코드로 실행되지 않도록 처리해야 한다.
가장 중요한 방법은 출력 시 HTML 이스케이프 처리이다.
예를 들어 <script>라는 값이 있을 때, 이를 그대로 출력하면 브라우저가 태그로 해석할 수 있다. 하지만 HTML 이스케이프 처리를 하면 다음처럼 변환된다.
<script>
<는 <, >는 >로 변환되기 때문에 브라우저는 이를 코드가 아니라 문자열로 표시한다.
XSS 방어 방법은 다음과 같다.
HttpOnly, Secure, SameSite 속성 설정여기서 중요한 점은 입력값 검증만으로는 부족할 수 있다는 것이다.
입력 단계에서 위험한 값을 걸러내는 것도 중요하지만, 최종적으로 화면에 출력할 때 안전하게 변환하는 처리가 필요하다.
또한 WAF는 XSS 공격 시도를 탐지하고 차단하는 데 도움을 줄 수 있지만, 근본적으로는 애플리케이션 코드에서 안전한 출력 처리가 적용되어야 한다.
즉, XSS 방어의 핵심은 사용자 입력값을 신뢰하지 않고, 브라우저가 코드로 해석하지 못하도록 안전하게 출력하는 것이다.
XSS는 공격자가 웹 페이지에 악성 스크립트를 삽입하여, 다른 사용자의 브라우저에서 실행되도록 만드는 공격이다.
XSS의 핵심은 사용자 입력값이 단순한 텍스트가 아니라 브라우저에서 실행 가능한 코드로 해석될 수 있다는 점이다.
따라서 개발자는 사용자 입력값을 신뢰하지 않고, 화면에 출력할 때 브라우저가 코드로 해석하지 못하도록 안전하게 처리해야 한다.