django.settings.py.Production Mode.security-headers
# Security Headers
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
본 기능은 HTTP 응답 헤더를 자동으로 추가해 보안을 강화하는 기능으로 django 가 자동으로 추가해 준다.
SECURE_BROWSER_XSS_FILTER = True
- 브라우저의 XSS(크로스 사이트 스크립트) 공격 방지 필터를 켜도록 지시한다.
- 예를 들어, 사용자가 입력한 악성 스크립트가 HTML에 삽입되더라도, 브라우저가 이를 차단하도록 도와준다.
- 헤더: X-XSS-Protection: 1; mode=block
SECURE_CONTENT_TYPE_NOSNIFF = True
- 브라우저가 응답의 Content-Type을 무시하고 임의로 다른 형식으로 "추측(sniffing)"하지 못하게 한다.
- 예를 들어, 서버가 text/plain을 보냈는데 브라우저가 text/html로 해석해서 스크립트를 실행하는 일을 막니다.
- 헤더: X-Content-Type-Options: nosniff
X_FRAME_OPTIONS = 'DENY'
- 사이트가 iframe 안에 삽입되는 것을 차단한다.
- 이걸 설정하지 않으면, 공격자가 당신의 사이트를 다른 페이지 iframe에 넣고, 클릭을 유도하는 Clickjacking 공격이 가능하다.
- 'DENY'는 완전 차단, 'SAMEORIGIN'은 같은 도메인에서만 허용.
SECURE_HSTS_SECONDS = 31536000
- HTTP Strict Transport Security (HSTS) 정책을 설정한다.
- HSTS 는 사용자가 HTTP가 아닌 HTTPS로만 웹사이트에 접근하도록 브라우저에 강제하는 정책이다.
- 서버가 응답 헤더에 Strict-Transport-Security를 포함하면, 브라우저는 이후 해당 사이트에 접속할 때 자동으로 HTTPS만 사용한다.
- 중간자 공격(MITM, Man in the Middle) 방지 및 쿠키 보안을 강화할 수 있다.
- 브라우저에게 “앞으로 1년(31536000초) 동안은 무조건 HTTPS로만 이 사이트에 접근해라”라고 알려줍니다.
- 헤더: Strict-Transport-Security: max-age=31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
- HSTS를 하위 도메인까지 강제 적용한다.
- 예: example.com뿐 아니라 sub.example.com도 HTTPS만 허용.
SECURE_HSTS_PRELOAD = True
- 사이트를 브라우저의 HSTS Preload List에 등록할 수 있도록 허용합니다.
- 이 리스트에 들어가면, 브라우저는 사용자가 처음 방문할 때부터 무조건 HTTPS로 접속하려고 합니다.
- (단, 실제 등록은 hstspreload.org 에서 직접 해야 함)
django.settings.py.Production Mode.SSL
# SSL Settings (Cloudflare handles SSL)
USE_TLS = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = False # Cloudflare handles this
USE_TLS = True
- 보통 SMTP 메일 전송(예: Gmail, 네이버 SMTP 서버 등)에서 TLS 암호화를 사용하도록 설정할 때 쓰인다.
- 즉, EMAIL_USE_TLS 같은 맥락일 가능성이 크고, SSL 전반을 켠다는 의미로 USE_TLS를 쓰는 건 Django 기본 설정에는 없음.
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
- Django는 기본적으로 요청이 HTTPS인지 HTTP인지 구분할 때 직접 받은 요청만 신뢰한다.
- 하지만 Cloudflare, Nginx 같은 리버스 프록시를 거치면,
- 클라이언트 → Cloudflare: HTTPS
- Cloudflare → Django: 보통 HTTP (내부 통신)
이런 구조가 돼서 Django는 "이 요청은 HTTP"라고 잘못 판단할 수 있습니다.
그래서 Cloudflare는 요청이 원래 HTTPS였다는 걸 알려주기 위해 X-Forwarded-Proto: https 헤더를 붙여준다.
SECURE_PROXY_SSL_HEADER는 Django에게
"이 헤더(HTTP_X_FORWARDED_PROTO)가 https라면, 요청은 HTTPS로 간주해라"
라고 알려주는 설정이다.
SECURE_SSL_REDIRECT = False
- Django에서 모든 요청을 자동으로 HTTPS로 리다이렉트하는 기능이다.
- True면 http:// 요청이 들어와도 자동으로 https://로 이동시킵니다.
- 하지만 지금은 False인데, 이유는 Cloudflare에서 이미 HTTP → HTTPS 리다이렉트를 처리하기 때문에 이중 리다이렉트가 일어나지 않도록 Django에서는 끈다.
django.settings.py.Production Mode.Session
# Session Security
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
Concepts
- Session 이란 서버에 저장되는 사용자 상태 정보이다. 웹은 기본적으로 무상태(stateless) 라서, 사용자가 로그인했는지 등 현재 상태를 모르기 때문에 어플리케이션 적으로 사용자 상태를 저장하는 것이 필요하다. 그 저장 장소 및 저장하는 방법을 'session' 이라 한다.
- Cookie 란 Session 과 반대로 서버의 지시사항을 브라우저에 저장하는 작은 데이터 조각이다. Session ID 를 저장해 사용자 인증을 유지시킨다. 사용자의 언어, 테마, 최근 본 상품 등 데이터를 저장해 브라우저 개인화를 실현한다.
# 서버가 Set-Cookie 헤더로 내려주면, 브라우저는 이를 저장하고 이후 요청마다 자동으로 Cookie 헤더에 붙여 서버로 전송한다.
Set-Cookie: theme=dark; Path=/; Secure; HttpOnly
- Session Cookie 란 Session ID 가 담긴 Cookie 를 말한다. 세션쿠키는 브라우저의 쿠키와 서버의 세션 저장소 두 곳에 저장한다.
SESSION_COOKIE_SECURE = True
- 세션 쿠키를 HTTPS 연결에서만 전송하도록 설정한다.
- HTTP(암호화되지 않은 통신)에서는 세션 쿠키가 절대 전송되지 않음 → 네트워크에서 세션 탈취 방지.
- 즉, 세션 쿠키가 평문으로 노출되지 않음.
CSRF_COOKIE_SECURE = True
- CSRF 방어를 위한 쿠키(csrftoken)도 HTTPS에서만 전송하도록 강제한다.
- 사용자가 로그인된 세션에서 CSRF 토큰이 탈취될 위험을 줄임.
SESSION_COOKIE_HTTPONLY = True
- 세션 쿠키에 JavaScript 접근을 차단한다.
- 즉, document.cookie 같은 JS 코드로 세션 쿠키를 읽을 수 없음.
- 이를 통해 XSS 공격으로 세션 쿠키가 탈취되는 것을 막아준다.
CSRF_COOKIE_HTTPONLY = True
- CSRF 토큰 쿠키에 대해서도 JavaScript 접근을 차단한다.
- 보안상 더 엄격해지지만, 주의할 점이 있음 👉
- Django 기본 CSRF 보호 방식은 쿠키에서 토큰을 읽어와서 HTML 폼에 삽입하기 때문에
CSRF_COOKIE_HTTPONLY = True를 켜면, JS가 쿠키에서 토큰을 직접 읽을 수 없게 된다. - 따라서 AJAX 요청 시 CSRF 토큰을 헤더에 추가하는 방식(예: <meta name="csrf-token" ...> 또는 Django csrftoken context)을 사용해야 한다.
- Django 기본 CSRF 보호 방식은 쿠키에서 토큰을 읽어와서 HTML 폼에 삽입하기 때문에
CORS (Cross-Origin Resource Sharing)
- 다른 출처(origin) 간의 자원 공유를 제어하는 메커니즘
- 브라우저 보안 정책 중 하나인 동일 출처 정책(Same-Origin Policy) 때문에 기본적으로 자바스크립트는 다른 도메인에서 제공하는 자원에 접근할 수 없다.
- 하지만 API 서버와 프론트엔드가 분리된 환경에서는 다른 출처 요청이 필요하므로, 이를 허용/제어하는 것이 CORS 이다.
- 즉, CORS 는 서버가 '어떤 외부 도메인에서 내 자원을 불러갈 수 있는지"를 브라우저에 알려주는 제도이다.
** 예시 **
내 사이트: https://frontend.com
API 서버: https://api.backend.com
프론트엔드에서 API 호출 시 브라우저가 막음 → Access-Control-Allow-Origin 헤더 필요
** 해결 방식 (서버에서 헤더 추가)**
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization
CSRF (Cross-Site Request Forgery)
- 사용자의 인증된 세션을 악용해, 원치 않는 요청을 강제로 보내는 공격
- 공격자는 사용자가 로그인된 상태임을 이용해서, 그 사람 몰래 서버에 요청을 보내도록 함.
- 사용자가 bank.com에 로그인해서 세션 쿠키를 가짐
- 공격자가 만든 사이트 evil.com을 방문
- evil.com에서 자동으로 bank.com/transfer?to=hacker&amount=1000 요청 실행
- 브라우저는 세션 쿠키를 자동으로 붙여 전송 → 사용자가 의도치 않게 송금 발생
- 방어 방법
- CSRF 토큰: 서버가 매 요청마다 난수 토큰을 발급하고, 클라이언트가 이를 요청과 함께 제출해야 함.
- SameSite 쿠키 속성: 크로스 사이트 요청에 쿠키가 자동 전송되지 않도록 제한.
'코딩' 카테고리의 다른 글
| SSO; Single Sign On (0) | 2025.09.04 |
|---|---|
| OAuth 2.0 (0) | 2025.09.03 |
| Gunicorn 설치 및 설정 (0) | 2025.08.26 |
| nginx 설치 및 설정 (0) | 2025.08.24 |
| Set up a Cloudflare Tunnel between local network and Cloudflare (0) | 2025.08.24 |