Web Security

XSS 방지책 (Flask)

꼰대코더 2025. 12. 2. 15:09

🛡️ Flask (CRUD API Only) XSS 방지 대책

API 서버에서 가장 중요한 XSS 방지책은 클라이언트 측에서 예상치 못한 방법으로 스크립트가 실행되는 것을 막는 것입니다.

1. 📝 입력 데이터 정제 (Input Sanitization)

Flask가 사용자로부터 받은 데이터를 데이터베이스에 저장하기 전, 또는 응답으로 보내기 전에 잠재적인 악성 HTML/스크립트 코드를 제거하는 과정입니다.

✅ 샘플 코드: bleach 라이브러리 사용

파이썬에서는 bleach와 같은 라이브러리를 사용하여 사용자 입력에서 HTML 태그와 속성을 안전하게 제거할 수 있습니다.

Bash
 
# 💡 라이브러리 설치
pip install bleach
Python
 
import bleach
from flask import Flask, request, jsonify

app = Flask(__name__)

# 허용할 HTML 태그 및 속성 목록 (API 서버이므로 모두 비워두는 것이 가장 안전)
ALLOWED_TAGS = []
ALLOWED_ATTRIBUTES = {}

@app.route('/api/posts', methods=['POST'])
def create_post():
    data = request.get_json()
    
    # ❌ 정제 없이 직접 사용 (위험!)
    # title = data.get('title') 
    
    # ✅ bleach를 사용하여 모든 HTML 태그를 제거하고 안전한 텍스트로 만듦
    raw_title = data.get('title', '')
    sanitized_title = bleach.clean(
        raw_title, 
        tags=ALLOWED_TAGS, 
        attributes=ALLOWED_ATTRIBUTES
    )
    
    # DB 저장 로직: sanitized_title을 저장
    # ...
    
    return jsonify({
        "message": "Post created successfully", 
        "title": sanitized_title
    }), 201

if __name__ == '__main__':
    app.run(debug=True)

설명: API 서버의 목적은 순수한 데이터 전송이므로, tags=[]로 설정하여 모든 HTML을 제거하고 순수한 텍스트만 남기도록 강제하는 것이 가장 안전합니다.


2. 🛡️ 보안 헤더 설정 (Security Headers)

API 응답에 보안 관련 HTTP 헤더를 추가하여, 설령 XSS 공격 코드가 삽입되더라도 브라우저가 이를 실행하는 것을 억제하도록 지시합니다.

✅ 샘플 코드: Content-Security-Policy 및 기타 헤더

after_request 훅을 사용하여 모든 API 응답에 자동으로 보안 헤더를 추가합니다.

Python
 
from flask import Flask, jsonify

app = Flask(__name__)

# ... (API 엔드포인트 코드) ...

@app.after_request
def add_security_headers(response):
    # 1. Content Security Policy (CSP) 설정
    # default-src 'self' : 모든 리소스(스크립트, 스타일 등)를 현재 도메인에서만 로드하도록 제한
    # object-src 'none' : <object>, <embed>, <applet> 태그 사용 금지
    response.headers['Content-Security-Policy'] = "default-src 'self'; object-src 'none';"
    
    # 2. X-Content-Type-Options: MIME 스니핑(Sniffing) 방지
    response.headers['X-Content-Type-Options'] = 'nosniff'
    
    # 3. X-Frame-Options: Clickjacking 방지 (API는 필요 없으나 일반 웹에선 중요)
    response.headers['X-Frame-Options'] = 'DENY'
    
    # 4. X-XSS-Protection (대부분의 모던 브라우저에서는 CSP로 대체됨)
    # response.headers['X-XSS-Protection'] = '0' # CSP 사용 시 비활성화 권장
    
    return response

# 예시 GET 엔드포인트
@app.route('/api/status', methods=['GET'])
def get_status():
    return jsonify({"status": "OK", "message": "Security headers applied."})

if __name__ == '__main.어요':
    app.run(debug=True)

설명:

  • CSP (Content-Security-Policy): 가장 강력한 방어 기제 중 하나입니다. default-src 'self'는 악성 스크립트가 외부 출처에서 로드되는 것을 차단합니다.
  • X-Content-Type-Options: nosniff: 브라우저가 응답의 MIME 타입을 추측하는 것을 막아, 서버가 text/plain이라고 보낸 응답을 브라우저가 강제로 text/html로 해석하여 실행하는 것을 방지합니다.

3. 🍪 HttpOnly 쿠키 사용

세션 관리나 인증에 쿠키를 사용할 경우, XSS 공격자가 사용자의 세션 토큰을 훔쳐가는 것을 막기 위해 이 설정을 반드시 적용해야 합니다.

✅ 샘플 코드: 쿠키 설정 시 httponly=True 옵션 사용

Python
 
from flask import make_response, jsonify

@app.route('/api/login', methods=['POST'])
def login():
    # ... 인증 로직 ...
    
    response = make_response(jsonify({"message": "Login successful"}))
    
    # ✅ HttpOnly 설정: 클라이언트 측 JavaScript에서 쿠키 접근 불가능
    # (XSS를 통한 세션 하이재킹 방지)
    response.set_cookie(
        'session_token', 
        'secure_random_token_value', 
        httponly=True, 
        secure=True, # HTTPS 환경에서만 전송
        samesite='Lax' # CSRF 방지에도 도움
    )
    
    return response

이 세 가지 방법을 통해 Flask API 서버는 사용자 입력 처리, 응답 헤더 설정, 세션 관리에 있어 강력한 XSS 방어 환경을 구축할 수 있습니다.