설명
크로스 사이트 요청 위조(Cross-Site Request Forgery, CSRF)는 악의적인 웹사이트가 사용자를 속여 다른 사이트에 대해 비정상적인 요청을 보내게 하는 공격입니다. 쿠키 등 브라우저가 자동으로 보내는 인증 정보를 이용해 공격자가 의도한 작업(예: 데이터 변경, 삭제 등)을 수행하게 만듭니다.
잠재적 영향
- 데이터 변조: 사용자의 의지와 상관없이 데이터가 변경될 수 있습니다.
- 사용자 권한 악용: 피해자에게 허용된 계정 설정 변경이나 관리 작업이 실행될 수 있습니다.
- 서비스 악용: 공격자가 서비스 기능을 악용하여 피해를 일으킬 수 있습니다.
해결 방법
- CSRF 방지 토큰 사용: 모든 상태 변경 요청에 대해 CSRF 방지 토큰을 사용합니다.
- 출처 검증: 서버에서
Origin등을 검증하여 신뢰할 수 없는 출처에서의 요청을 차단합니다. - 보안 설정 강화:
GET요청으로 상태를 변경하지 말고, HTTPS와 적절한SameSite쿠키 설정을 함께 적용합니다.
예시
Django
첫 예시는 CsrfViewMiddleware나 별도의 CSRF 보호가 없는 경우를 가정합니다. 데코레이터가 없다는 사실만으로 보호 부재를 판단할 수는 없습니다.
변경 전
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 검증 없이 POST 요청을 처리하여 CSRF 공격에 취약합니다.
- 변경 후:
@csrf_protect데코레이터를 사용하여 CSRF 토큰을 검증합니다.
Flask
Flask 예시는 your_secret_key 환경 변수에 충분히 강한 비밀 키가 설정되어 있다고 가정합니다. 보호된 폼이나 AJAX 요청에는 CSRF 토큰을 포함해야 합니다.
변경 전
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():
# CSRF 토큰을 검증하여 요청 처리
return "Request processed"
설명:
- 변경 전: CSRF 검증 없이 POST 요청을 처리하여 CSRF 공격에 취약합니다.
- 변경 후:
flask_wtf.csrf.CSRFProtect를 사용하여 CSRF 토큰을 검증합니다.
FastAPI
쿠키 인증을 사용하는 상태 변경 경로를 가정합니다. 두 번째 예시는 Origin이 없거나 허용 목록과 다르면 거부하는 출처 검증 예시이며, 인증·권한 확인은 별도로 구현해야 합니다.
변경 전
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 검증 없이 POST 요청을 처리하여 CSRF 공격에 취약합니다.
- 변경 후:
Origin검증이 허용하지 않은 출처의 요청을 차단합니다.TrustedHostMiddleware는 대상Host헤더를 검사하며, 그 자체로 CSRF를 방어하지는 않습니다.