설명
브라우저가 쿠키 같은 인증 정보를 자동으로 보내는 요청에서 출처 검증과 CSRF 방어가 부족하면, 공격자가 다른 사이트를 통해 사용자의 권한으로 원치 않는 요청을 보낼 수 있습니다. Origin 검증은 사용자 인증을 대신하지 않으며, 브라우저 외의 클라이언트는 이 헤더를 직접 지정할 수 있습니다.
잠재적 영향
- CSRF 공격: 공격자가 사용자를 대신하여 악의적인 요청을 보내어 무단 액세스를 시도할 수 있습니다.
- 데이터 유출: 요청으로 정보 공개나 전송 설정이 변경되면 민감한 데이터가 노출될 수 있습니다.
- 데이터 변조: 공격자가 데이터 변조를 시도하여 시스템 무결성을 손상시킬 수 있습니다.
해결 방법
- 서버에서 출처의 스킴, 호스트와 포트를 정확한 허용 목록과 비교하세요.
Origin누락과null출처를 어떻게 처리할지도 정하세요. - 브라우저의 쿠키 인증을 사용하는 상태 변경 요청에는 프레임워크의 CSRF 토큰 검증을 적용하세요.
- CORS는 신뢰하는 출처에만 응답을 읽을 수 있도록 설정하세요. CORS 설정만으로 CSRF 방어나 인증·권한 검사를 대신하지 마세요.
예시
쿠키 기반 인증을 사용하는 요청 처리의 일부입니다. 인증·권한 검사는 별도로 적용하세요. Flask의 your_secret_key 환경 변수에는 충분히 무작위인 비밀정보를 미리 공급하고, 클라이언트는 유효한 CSRF 토큰을 전송해야 합니다.
Django
변경 전
python
# Unsafe Django code
from django.http import HttpResponse
def my_view(request):
if request.method == 'POST':
# CSRF 검증 없이 요청 처리
return HttpResponse("Request processed")
변경 후
python
# Safe Django code
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_protect
@csrf_protect
def my_view(request):
if request.method == 'POST':
# CSRF 토큰을 검증하여 요청 처리
return HttpResponse("Request processed")
설명:
- 변경 전: 이 부분에는 CSRF 방어가 나타나지 않습니다. 다른 계층에서도 보호하지 않는 쿠키 인증 요청이라면 CSRF 공격에 노출될 수 있습니다.
- 변경 후:
@csrf_protect로 CSRF 검증을 적용합니다. 변경 전에도CsrfViewMiddleware가 활성화되어 있으면 보호될 수 있으므로 데코레이터의 부재만으로 판단하지 마세요.
Flask
변경 전
python
# Unsafe Flask code
from flask import Flask, request
app = Flask(__name__)
@app.route('/submit', methods=['POST'])
def submit():
# CSRF 검증 없이 요청 처리
return "Request processed"
변경 후
python
# Safe Flask code
import os
from flask import Flask, request
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv("your_secret_key").encode()
csrf = CSRFProtect(app)
@app.route('/submit', methods=['POST'])
def submit():
return "Request processed"
설명:
- 변경 전: 이 부분에는 CSRF 방어가 나타나지 않습니다. 다른 계층에서도 보호하지 않는 쿠키 인증 요청이라면 CSRF 공격에 노출될 수 있습니다.
- 변경 후:
flask_wtf.csrf.CSRFProtect를 사용하여 CSRF 토큰을 검증합니다.
FastAPI
변경 전
python
# Unsafe FastAPI code
from fastapi import FastAPI, Request
app = FastAPI()
@app.post("/submit")
async def submit(request: Request):
# CSRF 검증 없이 요청 처리
return {"message": "Request processed"}
변경 후
python
# Safe FastAPI code
from fastapi import FastAPI, Request, HTTPException
from starlette.middleware.trustedhost import TrustedHostMiddleware
app = FastAPI()
# 신뢰할 수 있는 호스트 설정
app.add_middleware(
TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"]
)
@app.post("/submit")
async def submit(request: Request):
origin = request.headers.get('origin')
if origin not in ["https://example.com", "https://www.example.com"]:
raise HTTPException(status_code=403, detail="Invalid origin")
# 요청 처리
return {"message": "Request processed"}
설명:
- 변경 전: 이 부분에는 CSRF 방어가 나타나지 않습니다. 다른 계층에서도 보호하지 않는 쿠키 인증 요청이라면 CSRF 공격에 노출될 수 있습니다.
- 변경 후:
Origin허용 목록에 없는 값과 누락된 헤더를 거부합니다.TrustedHostMiddleware는 요청 대상의Host를 검사하는 별도 기능이며 CSRF 방어를 대신하지 않습니다.