설정 중 DB 풀 설정, 로깅등은 제외하고 네트워크와 관련된 부분 알아보자.
from .base import *
import os
DEBUG = False
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(',')
SWAGGER_ENABLED = False
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(','): Host header attacks 방어.
# 보안 헤더 설정
SECURE_CROSS_ORIGIN_OPENER_POLICY = "same-origin"
SECURE_REFERRER_POLICY = 'strict-origin-when-cross-origin'
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
웹 애플리케이션의 기본적인 보안을 강화
SECURE_CROSS_ORIGIN_OPENER_POLICY = "same-origin": 다른 출처의 팝업 창이 현재 문서에 접근하는 것을 제한한다.
Clickjacking과 같은 공격을 완화하는 데 도움이 된다.
SECURE_REFERRER_POLICY = 'strict-origin-when-cross-origin': Referrer 정보를 보낼 때의 정책을 정의한다.
다른 출처로 요청을 보낼 때만 오리진 정보를 포함하고, HTTPS에서 HTTP로 요청할 때는 보내지 않아 민감 정보 노출을 방지한다.
SECURE_CONTENT_TYPE_NOSNIFF = True: 브라우저가 MIME type sniffing을 통해 콘텐츠 타입을 유추하는 것을 방지한다.
이는 악의적인 콘텐츠가 잘못된 타입으로 해석되어 실행되는 것을 막는다.
SECURE_BROWSER_XSS_FILTER = True: 브라우저 내장 XSS(Cross-Site Scripting) 필터를 활성화하여 XSS 공격을 방어한다.
# HTTPS 설정
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000 # 1년
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Nginx에서 이미 HTTPS 리다이렉션과 HSTS를 처리하고 있으면 필요없음 하지만 애플리케이션 레벨에서도 설정하여 혹시 모를 누락을 방지
SECURE_HSTS_SECONDS = 31536000 # (1년): HSTS(HTTP Strict Transport Security)를 활성화.
브라우저가 특정 기간(여기서는 1년) 동안 이 도메인에 대한 모든 요청을 HTTPS로만 보내도록 강제.
이는 중간자 공격(Man-in-the-Middle)을 통한 SSL 스트리핑 공격을 방지.
SECURE_HSTS_INCLUDE_SUBDOMAINS = True: HSTS 정책을 모든 서브도메인에도 적용한다.
SECURE_HSTS_PRELOAD = True: HSTS Preload List에 등록될 자격을 부여한다.
Preload List에 등록되면, 사용자가 도메인에 최초 접속 시에도 HTTP 요청을 보내지 않고 바로 HTTPS로 연결을 시도하게 된다.
# 세션 보안
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Strict' # 최고 보안
# CSRF 보안
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = 'Strict' # 최고 보안
쿠키를 통한 세션 및 CSRF 토큰 관리에 대한 보안 강화
SESSION_COOKIE_SECURE = True: 세션 쿠키가 HTTPS 연결을 통해서만 전송되도록
SESSION_COOKIE_HTTPONLY = True: 자바스크립트가 세션 쿠키에 접근하는 것을 방지.
XSS 공격 시 쿠키 탈취를 어렵게 만듦
SESSION_COOKIE_SAMESITE = 'Strict': CSRF(Cross-Site Request Forgery) 공격을 방지하는 강력한 방법
'Strict' 모드는 동일 사이트 요청(Same-site request)에서만 쿠키가 전송되도록 한다.
(예: 다른 사이트에서 링크를 통해 접속하더라도 해당 사이트의 쿠키는 전송되지 않음.)
이는 보안을 크게 강화하지만, 경우에 따라 Lax 모드가 더 적합할 수도 있음.
CSRF_COOKIE_SECURE = True, CSRF_COOKIE_HTTPONLY = True, CSRF_COOKIE_SAMESITE = 'Strict': CSRF 토큰 쿠키에도 세션 쿠키와 동일한 강력한 보안 설정이 적용
# CORS 설정 (프로덕션 - 제한적)
CORS_ALLOW_ALL_ORIGINS = False
CORS_ALLOWED_ORIGINS = os.getenv('CORS_ALLOWED_ORIGINS', '').split(',')
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = ( ... )
CORS_ALLOW_HEADERS = ( ... )
CORS_ALLOW_ALL_ORIGINS = False: 모든 출처에서의 CORS 요청을 허용하지 않음.
보통은 /api/ 로 경로를 나누어 요청하는 것이 일반적이지만 팀원의 요청으로 인하여 :8000 로 분기처리를 하였다.
server {
listen 80;
listen [::]:80;
server_name cnn.parking.monster;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name cnn.parking.monster;
# SSL 설정 (참고로 아래 경로들은 cerbot 를 사용했다면 기본 경로들)
ssl_certificate /etc/letsencrypt/live/[도메인 네임]/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/[도메인 네임]/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# 보안 헤더 (옵션, 권장)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 파일 업로드 크기 제한 (옵션)
client_max_body_size 10M;
# 타임아웃 설정 (옵션)
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# API 엔드포인트 (옵션 -> 여기선 8000 포트로 나눔.)
location /api/ {
proxy_pass http://unix:/run/gunicorn.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# WebSocket 지원 (옵션)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 버퍼링 설정 (옵션)
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
# 정적 파일 서빙
location / {
root [build 파일 위치];
try_files $uri $uri/ /index.html;
# 404 에러 처리
error_page 404 /index.html;
# HTML 파일 캐싱 방지
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate, proxy-revalidate";
add_header Pragma "no-cache";
add_header Last-Modified $date_gmt;
add_header ETag "";
if_modified_since off;
}
# 정적 자원 캐싱
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|webp|woff|woff2|ttf|eot|map)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
# Gzip 압축 활성화 (옵션)
gzip_static on;
}
}
# 로그 설정
access_log /var/log/nginx/cnn.parking.monster.access.log;
error_log /var/log/nginx/cnn.parking.monster.error.log;
}
server {
listen 8000 ssl http2;
listen [::]:8000 ssl http2;
server_name [도메인 네임];
# SSL 설정
ssl_certificate /etc/letsencrypt/live/[도메인 네임]/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/[도메인 네임]/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# 보안 헤더
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
# 파일 업로드 크기 제한 (옵션)
client_max_body_size 10M;
# 타임아웃 설정
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
location / {
proxy_pass http://unix:/run/gunicorn.sock;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# HTTP 버전 및 버퍼링 설정
proxy_http_version 1.1;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
# 로그 설정
access_log /var/log/nginx/cnn.parking.monster.8000.access.log;
error_log /var/log/nginx/cnn.parking.monster.8000.error.log;
}