FastAPI의 CSP 설정 중 Swagger 빈 화면 출력 문제
✒️ 2026-03-01 12:58 내용 수정
📋 문제 개요
문제 설명
FastAPI의 보안 헤더 설정 중 CSP(Content-Security-Policy)을 적용한 후 Swagger 문서에 접근했을 때 아무 내용이 없는 흰 화면만 발생
🔍 상세 정보
발생 환경
- 환경: 개발
- 서버/인스턴스: FastAPI 0.128.0
- 브라우저/디바이스: Chrome
- 관련 버전:
재현 방법
- 보안 헤더 설정 중 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';"
)
- 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
🔎 원인 분석
조사 과정
- MS Copilot으로 문제 분석 진행
근본 원인
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 차단
- 증상
Loading the stylesheet '<https://cdn.jsdelivr.net/.../swagger-ui.css>' violates ... "style-src 'self' 'unsafe-inline'" ... - 원인
style-src에 외부 출처가 없었기 때문에, Swagger UI CSS를 호스팅하는 jsDelivr가 차단됨. CSP에서 스타일 로드는style-src가 담당하며,style-src-elem을 지정하지 않으면style-src가 대체로 사용됨. - 조치
style-src 'self' 'unsafe-inline' <https://cdn.jsdelivr.net>;추가(또는 자가 호스팅 시'self'만).
2) 외부 JS 차단
- 증상
Loading the script '<https://cdn.jsdelivr.net/.../swagger-ui-bundle.js>' violates ... "script-src 'self'" ... - 원인
script-src에 외부 출처가 없었기 때문에 jsDelivr의 JS가 차단됨.script-src는 스크립트 로드를 제어함. - 조치
script-src 'self' <https://cdn.jsdelivr.net>;추가(또는 자가 호스팅 시'self'만).
3) 인라인 스크립트 차단
- 증상
Executing inline script violates ... 'script-src 'self'' ... either 'nonce-...' or a hash('sha256-...') is required - 원인 Swagger UI 문서 HTML 내부에 인라인 스크립트가 있으며, 기본
script-src정책은 인라인 실행을 금지함. 인라인을 허용하려면 해시 또는 nonce가 필요. (구성/버전에 따라 인라인 의존성이 일부 남아 있을 수 있음) - 조치
- 가장 안전:
'sha256-...'해시(혹은 nonce)를script-src에 추가하여 해당 인라인만 정확히 허용. - 임시 조치(권장 X):
'unsafe-inline'추가. FastAPI가 기본으로 읽어들이는 Swagger UI 버전과 인라인 의존성은 버전에 따라 다르므로 가능하면 최신(또는 안정) 버전으로 고정/업데이트하면 충돌이 줄어듦.
- 가장 안전:
4) CSS 소스맵(.css.map) 요청 차단
- 증상
Connecting to '<https://cdn.jsdelivr.net/.../swagger-ui.css.map>' violates ... "default-src 'self'". 'connect-src' was not explicitly set, so 'default-src' is used as a fallback. - 원인 연결 계열 요청(XHR/fetch/WebSocket 등)은 CSP의
connect-src가 담당하는데, 명시가 없어서default-src 'self'가 대신 적용되어 jsDelivr로의 연결이 차단됨. 소스맵 요청은 스타일 로드가 아니라 네트워크 연결로 분류되어connect-src에 걸림. - 조치
connect-src 'self' <https://cdn.jsdelivr.net>;추가(또는 전면 https: 허용은 테스트용)
✅ 해결 방법
적용한 솔루션
- 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>;"
)