CSP가 없으면 XSS는 막을 방법이 없다
XSS(Cross-Site Scripting)는 웹 취약점 중 발생 빈도 1위를 놓친 적이 없다. 공격자가 악성 스크립트를 페이지에 심으면 쿠키 탈취, 피싱 페이지 전환, 키로깅이 가능해진다.
CSP(Content Security Policy)는 브라우저에게 "이 페이지에서는 이 출처의 스크립트만 실행해"라고 명시적으로 지시하는 헤더다. 이게 설정되어 있으면 인라인 스크립트 주입 자체가 차단된다.
CSP 기본 문법
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src *; object-src 'none'
주요 디렉티브 설명:
- default-src 'self': 기본적으로 같은 출처만 허용
- script-src: JavaScript를 허용할 출처
- style-src: CSS를 허용할 출처
- img-src: 이미지 출처
- object-src 'none': Flash 등 플러그인 완전 차단
실전에서 바로 쓸 수 있는 설정
Nginx 설정
add_header Content-Security-Policy "
default-src 'self';
script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https:;
connect-src 'self' https://api.yourservice.com;
frame-ancestors 'none';
object-src 'none';
base-uri 'self'
" always;
Django 미들웨어로 적용
class CSPMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
response['Content-Security-Policy'] = (
"default-src 'self'; "
"script-src 'self'; "
"object-src 'none'; "
"frame-ancestors 'none';"
)
return response
바로 적용하기 무서우면 — Report-Only 모드
CSP를 갑자기 적용하면 기존 스크립트가 막혀서 서비스가 깨질 수 있다. 이럴 때는 Content-Security-Policy-Report-Only 헤더로 먼저 모니터링만 한다.
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
이 모드에서는 위반이 발생해도 차단하지 않고 report-uri로 위반 내역만 전송한다. 2~3주 운영하면서 어떤 출처가 필요한지 파악한 뒤 실제 CSP에 추가하는 방식이 안전하다.