파이썬/Fast API

FastAPI Response Set-Cookie와 HttpOnly 보안 구현

코샵 2025. 2. 27. 10:26
반응형

FastAPI에서 HttpOnly 쿠키를 설정하여 보안을 강화하는 방법을 알아보겠습니다.

기본 쿠키 설정

from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse

app = FastAPI()

@app.post("/login")
async def login(response: Response):
    # 기본적인 쿠키 설정
    response.set_cookie(
        key="session",
        value="abc123",
        httponly=True,
        secure=True,
        samesite='lax',
        max_age=1800  # 30분
    )
    return {"message": "로그인 성공"}

보안 옵션 설정 비교

옵션 설명 권장 설정
httponly JavaScript 접근 차단 True
secure HTTPS에서만 전송 True
samesite CSRF 보호 'lax' 또는 'strict'
max_age 쿠키 유효 기간 세션에 따라 적절히 설정
domain 쿠키 도메인 필요한 경우만 설정
path 쿠키 경로 기본값 '/' 권장

실제 구현 예시

from fastapi import FastAPI, Response, HTTPException
from datetime import datetime
import jwt

app = FastAPI()

SECRET_KEY = "your-secret-key"

@app.post("/login")
async def login(username: str, password: str, response: Response):
    # 인증 로직
    if not authenticate_user(username, password):
        raise HTTPException(status_code=401, detail="인증 실패")

    # JWT 토큰 생성
    token = jwt.encode(
        {
            "sub": username,
            "exp": datetime.utcnow() + timedelta(minutes=30)
        },
        SECRET_KEY,
        algorithm="HS256"
    )

    # 보안 쿠키 설정
    response.set_cookie(
        key="session_token",
        value=token,
        httponly=True,
        secure=True,
        samesite='lax',
        max_age=1800,
        path="/"
    )

    return {"message": "로그인 성공"}

쿠키 관리 유틸리티

class CookieManager:
    def __init__(self, response: Response):
        self.response = response

    def set_secure_cookie(
        self,
        key: str,
        value: str,
        max_age: int = 1800,
        secure: bool = True
    ):
        self.response.set_cookie(
            key=key,
            value=value,
            httponly=True,
            secure=secure,
            samesite='lax',
            max_age=max_age,
            path="/"
        )

    def delete_cookie(self, key: str):
        self.response.delete_cookie(
            key=key,
            path="/",
            httponly=True
        )

@app.post("/auth")
async def auth_handler(response: Response):
    cookie_manager = CookieManager(response)
    cookie_manager.set_secure_cookie("auth_token", "user_token")
    return {"status": "success"}

전역 미들웨어 설정

from fastapi.middleware.base import BaseHTTPMiddleware
from fastapi import Request

class SecurityHeadersMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        response = await call_next(request)
        response.headers['X-Content-Type-Options'] = 'nosniff'
        response.headers['X-Frame-Options'] = 'DENY'
        response.headers['X-XSS-Protection'] = '1; mode=block'
        return response

app.add_middleware(SecurityHeadersMiddleware)

쿠키 검증과 처리

from fastapi import Cookie, Depends

async def verify_token(
    session_token: str = Cookie(None)
) -> dict:
    if not session_token:
        raise HTTPException(
            status_code=401,
            detail="인증되지 않은 요청"
        )

    try:
        payload = jwt.decode(
            session_token,
            SECRET_KEY,
            algorithms=["HS256"]
        )
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=401,
            detail="토큰 만료"
        )
    except jwt.JWTError:
        raise HTTPException(
            status_code=401,
            detail="유효하지 않은 토큰"
        )

@app.get("/protected")
async def protected_route(payload: dict = Depends(verify_token)):
    return {"user": payload["sub"]}

 

HttpOnly 쿠키를 사용할 때 주의할 점

  1. 보안 설정
    • 항상 httponly=True 설정
    • 가능한 경우 secure=True 사용
    • 적절한 samesite 정책 적용
  2. 에러 처리
    • 쿠키 누락 상황 처리
    • 만료된 쿠키 처리
    • 잘못된 형식의 쿠키 처리
  3. 세션 관리
    • 적절한 만료 시간 설정
    • 세션 갱신 메커니즘 구현
    • 로그아웃 시 쿠키 삭제

이러한 보안 설정을 통해 XSS와 CSRF 같은 일반적인 웹 취약점으로부터 애플리케이션을 보호할 수 있습니다.