
웹 보안의 세계에서 XSS(Cross-Site Scripting)는 가장 흔하게 발견되는 취약점 중 하나이며, 이 중에서도 "Reflected XSS(반사형 XSS)"는 비교적 발견이 쉽고 빠르게 악용될 수 있어 실무에서 특히 주의가 필요합니다. 사용자 입력값이 서버에서 필터링 없이 바로 응답에 반영될 경우, 공격자는 URL을 조작해 악성 스크립트를 삽입하고 제3자에게 전달함으로써 피해를 유발할 수 있습니다.
사용자가 어떤 경고도 없이 조작된 링크를 클릭했을 때, 예상치 못한 스크립트가 즉시 브라우저에서 실행되는 상황에는 사용자의 개입 없이 악성 스크립트가 실행되며, 개인 정보 탈취, 악성 웹사이트로의 리디렉션, 브라우저 세션 탈취 등이 가능해집니다. 특히 "Reflected XSS"는 인증되지 않은 사용자에게도 쉽게 노출될 수 있어, 시스템 접근 권한이 없는 공격자라도 공격을 실행할 수 있다는 점에서 매우 위험합니다. 일상적인 검색창이나 에러 메시지에도 삽입이 가능하기 때문에 더욱 경각심이 필요합니다.
Reflected XSS란?
"Reflected XSS"는 사용자의 입력값이 서버를 거쳐 검증 없이 HTML 응답에 그대로 포함될 때 발생하는 공격 방식입니다. 보통 다음과 같은 경로로 동작합니다:
- 사용자가 검색어, 피드백, 에러 메시지 등으로 특정 값을 입력
- 해당 값이 서버 응답 내 HTML이나 JavaScript 코드에 포함됨
- 공격자가 이를 악용해 악성 스크립트를 삽입한 URL을 생성
- 사용자가 해당 URL을 클릭하면 스크립트가 실행됨
이러한 구조는 특히 검색 기능, 오류 페이지, 쿼리 스트링 등을 처리하는 페이지에서 자주 발견되며, 대응이 미흡할 경우 단 몇 줄의 스크립트로도 정보 탈취가 가능합니다.
예시: 검색창을 통한 XSS 유도
<!-- 취약한 HTML 코드 -->
<p>You searched for: <%= query %></p>
공격자는 다음과 같은 URL을 생성할 수 있습니다:
https://example.com/search?query=<script>alert('XSS')</script>
이 URL을 이메일, 게시판, 메시지 등으로 다른 사용자에게 전달하면, 피해자는 해당 페이지를 열었을 때 입력값이 화면에 그대로 출력되면서 스크립트가 실행되는 구조입니다.
취약한 코드 vs 안전한 코드 비교
취약한 구조
<?php
$name = $_GET['name'];
echo "Hello, $name";
?>
공격자가 입력한 값
<script>alert('XSS')</script>
보완된 안전한 코드 예제
<?php
$name = htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');
echo "Hello, $name";
?>
htmlspecialchars 함수는 HTML에서 사용되는 특수 문자를 이스케이프 처리하여, 스크립트가 브라우저에서 실행되지 않도록 방지합니다. 이는 가장 기본적인 대응책으로, 모든 사용자 입력값에 적용해야 합니다.
대응 방법
입력값 검증(Input Validation)
- 숫자, 이메일, 고정된 문자열 등으로 제한 가능성이 있는 값은 정규식을 통해 형식을 검증
- HTML, JavaScript 코드가 삽입되지 않도록 서버 단에서 차단
출력 이스케이프(Output Encoding)
- HTML 문맥:
htmlspecialchars,htmlentities - JavaScript 문맥: 템플릿 내
JSON.stringify, 문자열 처리 시\이스케이프 - URL 문맥:
urlencode,encodeURIComponent
보안 정책 적용
- CSP(Content Security Policy): 외부 스크립트 실행 제한, 인라인 스크립트 차단 등 강력한 보안 헤더 설정
- WAF(Web Application Firewall): 자주 알려진 XSS 패턴을 실시간으로 탐지 및 차단
이러한 대응책은 단독으로 적용하기보다는, 입력 검증 → 출력 이스케이프 → 정책 적용이라는 다층적 방식으로 구성하는 것이 효과적입니다.
참고 자료 및 공식 문서
Reflected XSS는 단순하지만 강력한 위협입니다. 공격자는 시스템의 복잡한 구조를 분석하지 않고도, 단지 사용자 입력값의 검증이 부실한 지점을 노려 피해를 일으킬 수 있습니다. 개발자와 보안 담당자는 사용자 입력을 절대 신뢰하지 말고, 모든 출력값에 대해 문맥에 맞는 이스케이프 처리를 기본 원칙으로 삼아야 합니다. 이를 통해 사용자의 안전을 보장하고, 서비스의 신뢰성을 지킬 수 있습니다.