본문 바로가기
시큐어코딩/Python

[시큐어코딩]XSS(크로스사이트 스크립팅) 방어 패턴과 Django의 보안 미들웨어 설정법

by ICT리더 리치 2025. 4. 21.
반응형

"단 한 줄의 스크립트로 사용자 정보를 탈취할 수 있다면?" XSS는 실무에서 자주 놓치는 치명적 공격입니다.

안녕하세요. 이번 글에서는 실무에서 특히 많이 발생하는 XSS(크로스사이트 스크립팅) 취약점에 대해 알아보고, 이를 효과적으로 방어하기 위한 시큐어코딩 패턴과 함께 Django에서 제공하는 보안 미들웨어 설정 방법까지 단계적으로 설명드리겠습니다.

XSS는 입력값 검증 누락 또는 출력 필터링 미흡으로 인해 공격자가 악의적인 스크립트를 주입할 수 있는 취약점입니다. 단순한 게시판, 댓글 입력란, 검색어 필드 등 대부분의 폼 요소에서 발생할 수 있어 대응이 반드시 필요합니다.

보안 설정을 개발 중인 20대 한국 여성 Django 개발자
HTTPS 보안 환경에서 Django 웹 애플리케이션을 개발하는 20대 한국 여성 개발자

1. XSS란 무엇인가?

XSS(Cross-Site Scripting)는 웹 애플리케이션에 악성 스크립트를 주입하여 사용자 브라우저에서 실행되도록 하는 공격입니다. 가장 흔한 예는 로그인 쿠키 탈취, 피싱 페이지 삽입, 키로깅 등이며, 사용자의 세션 하이재킹에도 악용될 수 있습니다.

공격자는 게시판, 검색창, 댓글 입력란 등 사용자 입력이 포함되는 부분을 통해 다음과 같은 스크립트를 삽입할 수 있습니다:

<script>alert('XSS 공격 성공!')</script>

이처럼 단 한 줄의 코드로도 사용자의 정보를 탈취하거나 시스템의 신뢰성을 무너뜨릴 수 있기 때문에, 모든 사용자 입력은 무조건 "신뢰할 수 없는 데이터"로 취급해야 합니다.

2. 대표적인 XSS 공격 유형

XSS는 그 동작 방식에 따라 보통 3가지 유형으로 분류됩니다. 각각의 공격 방식은 구현 구조나 처리 방식에 따라 달라지며, 아래에 요약합니다.

유형 설명 예시
Stored XSS 입력된 스크립트가 DB 등에 저장되어 다른 사용자에게 전달됨 게시판, 댓글, 프로필 입력 등
Reflected XSS 입력값이 즉시 응답에 반영되며 실행됨 검색창, URL 쿼리 파라미터
DOM-based XSS JavaScript가 DOM을 조작하며 악성 스크립트 실행 클라이언트에서 location.hash, innerHTML 등 조작

이러한 공격은 단독으로 발생하지 않고, 종종 피싱이나 세션 탈취와 결합하여 더 큰 피해로 이어집니다.
Django 같은 프레임워크에서도 완전한 방어를 위해선 코드레벨 대응이 병행되어야 합니다.

3-1. 입력 및 출력단 방어 패턴 I

XSS는 입력값을 신뢰하지 않고, 출력 시 반드시 이스케이프 처리를 하는 것이 핵심 방어 전략입니다. Django에서는 다음과 같은 방식으로 방어할 수 있습니다.

  • 입력단 필터링: form field에 validators를 지정하여 위험한 문자열을 차단
  • 출력단 이스케이프: Django 템플릿은 기본적으로 자동 escape 기능이 적용됨 ({{ value }})
  • 직접 출력 시 escape 함수 사용: django.utils.html.escape() 사용
  • 정적 자바스크립트 생성 시 주의: 데이터를 HTML에 직접 바인딩하지 말고, data-* 속성 활용

❌ [취약한 출력 코드 예시]

<div>{{ user_input|safe }}</div>

 

✅ [안전한 출력 코드 예시]

<div>{{ user_input }}</div>

템플릿에서 |safe 필터를 무분별하게 사용하면, 자동 이스케이프가 무력화되어 치명적인 취약점을 만들 수 있습니다. 반드시 신뢰된 데이터에만 제한적으로 사용해야 합니다.

3-2. 입력 및 출력단 방어 패턴 II

XSS 공격은 대부분 입력값을 필터링하지 않고 출력할 때 발생합니다. 따라서 안전한 코딩을 위해선 사용자의 입력을 신뢰하지 말고, 출력 시 자동 이스케이프 기능을 활용해야 합니다.

 

❌ 취약한 예제: 사용자의 입력을 그대로 출력할 경우


# views.py (취약한 예시)
from django.http import HttpResponse

def unsafe_view(request):
    comment = request.GET.get("comment")  # 사용자 입력
    return HttpResponse(f"댓글: {comment}")  # 이스케이프 없음!

위 코드는 사용자 입력에 스크립트가 포함될 경우, 그대로 HTML에 삽입되어 실행될 수 있는 전형적인 XSS 취약점입니다.

 

✅ 안전한 예제: 입력 필터링 + 자동 이스케이프 사용 + CSP 적용


# forms.py
from django import forms

class CommentForm(forms.Form):
    content = forms.CharField(
        max_length=200,
        widget=forms.Textarea(attrs={"rows": 3}),
        strip=True
    )

# views.py
from django.shortcuts import render
from .forms import CommentForm

def safe_view(request):
    if request.method == "POST":
        form = CommentForm(request.POST)
        if form.is_valid():
            content = form.cleaned_data["content"]
            return render(request, "result.html", {"content": content})
    else:
        form = CommentForm()
    return render(request, "comment.html", {"form": form})

# result.html
<!-- 템플릿에서는 자동 이스케이프로 안전하게 출력 -->
<p>입력한 댓글: {{ content }}</p>

 

Django 템플릿은 기본적으로 {{ content }}에서 HTML 이스케이프를 적용하기 때문에, 스크립트 공격을 그대로 실행하지 않습니다. 여기에 forms를 통한 입력 검증까지 더하면 이중으로 방어가 가능합니다.

 

💡 추가 팁: Content-Security-Policy 헤더를 설정하면, 악성 스크립트의 실행을 원천 차단할 수 있어 매우 강력한 XSS 대응책이 됩니다.

4. Django 보안 미들웨어 설정 방법

Django는 기본적으로 XSS 방어에 도움이 되는 보안 미들웨어를 제공합니다. 특히 HTTP 헤더 수준에서 스크립트 실행을 제한하거나, 브라우저 보안 정책을 강화하는 방식으로 작동합니다.

1) XSS Protection 헤더 활성화

# settings.py
SECURE_BROWSER_XSS_FILTER = True

브라우저의 XSS 필터 기능을 활성화하여, 의심되는 스크립트 차단

2) 콘텐츠 보안 정책 (Content-Security-Policy)

# settings.py
MIDDLEWARE = [
    ...,
    'csp.middleware.CSPMiddleware',
]

CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'", 'cdnjs.cloudflare.com')  # 외부 스크립트 허용 범위 제한

불필요한 외부 JS의 로드를 막고, 특정 도메인만 허용하도록 설정할 수 있습니다.

3) HTML 메타 태그 차단 권장

<meta http-equiv="Content-Security-Policy" content="default-src 'self'">

이 외에도 SECURE_CONTENT_TYPE_NOSNIFF, X_FRAME_OPTIONS 같은 보안 관련 설정들을 함께 적용하면 더욱 강력한 보안을 확보할 수 있습니다.

※ 주의: CSP 적용 시 JS, 폰트, 이미지 등의 로딩 이슈가 발생할 수 있으므로, 허용 도메인을 테스트하면서 천천히 적용하세요.

5. 자주 묻는 질문 (FAQ)

Q Django 템플릿의 |safe 필터는 언제 사용하나요?

|safe는 신뢰할 수 있는 HTML 출력 시에만 사용하세요. 사용자 입력 값에는 절대 적용하지 않는 것이 원칙입니다. 보안 검증된 콘텐츠에만 한정적으로 적용하세요.

Q HTML 이스케이프는 Django에서 자동 적용되나요?

네, 기본적으로 {{ 변수 }} 출력 시 Django 템플릿 엔진은 자동으로 HTML 이스케이프 처리를 해줍니다. 단, |safe 필터를 사용하면 이 기능이 해제되므로 주의가 필요합니다.

Q Content-Security-Policy(CSP)는 반드시 적용해야 하나요?

CSP는 XSS 방어에 강력한 보호막이 됩니다. 특히 외부 JS 사용이 많은 프로젝트에서는 필수로 고려해야 하며, 초기에는 report-only 모드로 시작해 점진적으로 적용하는 것이 좋습니다.

 

지금까지 Django 환경에서 XSS 공격을 어떻게 방어하고, 시큐어코딩 및 보안 미들웨어를 어떻게 적용할 수 있는지에 대해 알아보았습니다. 보안은 한 번의 설정으로 끝나는 것이 아니라, 꾸준히 점검하고 업데이트해야 하는 개발 문화입니다. 실무에 적용하면서 보안 수준을 높여가는 데 이번 가이드가 도움이 되었기를 바랍니다.

반응형