FastAPI의 CSP 설정 중 Swagger 빈 화면 출력 문제

✒️ 2026-03-01 12:58 내용 수정


📋 문제 개요

문제 설명

FastAPI의 보안 헤더 설정 중 CSP(Content-Security-Policy)을 적용한 후 Swagger 문서에 접근했을 때 아무 내용이 없는 흰 화면만 발생


🔍 상세 정보

발생 환경

재현 방법

  1. 보안 헤더 설정 중 CSP(Content-Security-Policy) 설정을 다음과 같이 적용
CSP_SWAGGER = (
    "default-src 'self'; "
    "base-uri 'self'; "
    "object-src 'none'; "
    "frame-ancestors 'none'; "
    "img-src 'self' data: https:; "
    "style-src 'self' 'unsafe-inline'; "
    "script-src 'self';"
)
  1. Chrome으로 FastAPI의 Swagger 커스텀 경로인 /docs 로 접근

에러 메시지 및 로그

Loading the stylesheet '<https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css>' violates the following Content Security Policy directive: "style-src 'self' 'unsafe-inline'". Note that 'style-src-elem' was not explicitly set, so 'style-src' is used as a fallback. The action has been blocked.Understand this error
docs:1 Loading the script '<https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js>' violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback. The action has been blocked.Understand this error
docs:14 Executing inline script violates the following Content Security Policy directive 'script-src 'self''. Either the 'unsafe-inline' keyword, a hash ('sha256-/...'), or a nonce ('nonce-...') is required to enable inline execution. The action has been blocked.Understand this error

🔎 원인 분석

조사 과정

근본 원인

Swagger UI가 외부 CDN(jsDelivr)에서 CSS/JS를 가져오는데(그리고 일부 인라인 실행도 사용), 서버의 CSP가 외부 출처와 인라인 실행을 기본 차단했기 때문에 오류가 발생했다.
FastAPI의 기본 get_swagger_ui_html()는 기본적으로 https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/...에서 리소스를 불러오도록 되어 있다.
따라서 해당 CDN을 CSP에 명시적으로 허용(그리고 필요한 경우 인라인 실행은 해시/nonce로 허용)해야 한다.

1) 외부 CSS 차단

2) 외부 JS 차단

3) 인라인 스크립트 차단

4) CSS 소스맵(.css.map) 요청 차단


✅ 해결 방법

적용한 솔루션

  1. CSP 설정을 다음과 같이 변경
    • 외부 CSS, JS, 인라인 스크립트, CSS 소스맵 요청을 외부에서 가져오도록 허용
CSP_SWAGGER = (
    "default-src 'self'; "
    "base-uri 'self'; "
    "object-src 'none'; "
    "frame-ancestors 'none'; "
    "img-src 'self' data: https:; "
    "style-src 'self' 'unsafe-inline' <https://cdn.jsdelivr.net>; "
    "script-src 'self' 'sha256-<콘솔에 표시된 해시>' <https://cdn.jsdelivr.net>;"
    "connect-src 'self' <https://cdn.jsdelivr.net>;"
)