aio2o-infrakit/config/web-server/nginx/gunicorn/report.md

20 KiB
Raw Blame History

Nginx HTTPS 설정 검토 보고서

요약

본 보고서는 sample_nginx_https.conf (템플릿)와 https.conf (code.devspoon.com의 운영 설정)을 비교하고, 현재 설정의 운영 준비 상태를 평가합니다.

종합 평가: https.conf는 샘플 템플릿보다 훨씬 더 운영 환경에 적합하며, 최신 보안 헤더와 우수한 설정을 갖추고 있습니다. 그러나 일부 개선 사항이 권장됩니다.


1. 설정 비교 분석

1.1 HTTP 서버 블록 (포트 80)

샘플 설정의 문제점:

server {
    listen       portnumber;
    server_name  domain www.domain;

    rewrite ^ https://$host$request_uri permanent;

    # if ($host !~* ^(domain\.com|www\.domain\.com)$) {
    #     return 444;
    # }
}

문제점:

  • 일반적인 플레이스홀더 사용 (portnumber, domain)
  • return 301 대신 더 이상 권장되지 않는 rewrite 지시어 사용
  • 호스트 검증이 주석 처리됨
  • Let's Encrypt ACME 챌린지 location 누락

운영 설정 (https.conf) - 올바름:

server {
    listen       80;
    server_name  code.devspoon.com www.code.devspoon.com;

    # 리다이렉트 전 호스트 검증
    if ($host !~* ^(code\.devspoon\.com|www\.code\.devspoon\.com)$) {
        return 444;
    }

    # 리다이렉트 전 ACME 챌린지
    location ^~ /.well-known/acme-challenge/ {
        allow all;
        root /www/certbot;
        try_files $uri =404;
    }

    # HTTPS로 리다이렉트
    location / {
        return 301 https://$server_name$request_uri;
    }
}

장점: return 301 사용 (rewrite보다 효율적) 호스트 검증 활성화 리다이렉트 전 ACME 챌린지 적절히 처리 location 블록으로 더 나은 구조 $host 대신 $server_name 사용 (더 안전함)


1.2 HTTPS 서버 블록 (포트 443)

SSL/TLS 설정

샘플 설정 - 구식:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

운영 설정 - 최신 & 올바름:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;  # TLSv1.3에서는 OFF
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

분석:

  • 운영 설정에서 ssl_prefer_server_ciphers off 사용 - TLSv1.3에 올바름 (클라이언트 선호가 더 나음)
  • 일반적인 약칭 대신 명시적이고 최신 암호화 스위트 사용
  • 모바일 장치 최적화를 위한 CHACHA20-POLY1305 포함

1.3 보안 헤더

샘플 설정 - 누락:

  • 보안 헤더가 전혀 없음

운영 설정 - 우수:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss: ws:;" always;

평가: HSTS (preload 포함) - 다운그레이드 공격 방지 X-Frame-Options - 클릭재킹 방지 X-Content-Type-Options - MIME 스니핑 방지 X-XSS-Protection - 레거시 XSS 보호 Referrer-Policy - 리퍼러 정보 제어 CSP - XSS 방지를 위한 콘텐츠 보안 정책 모든 헤더에 always 플래그 사용 - 오류 응답에도 헤더 보장


1.4 OCSP 스테이플링

샘플 설정 - 누락

운영 설정 - 구현됨:

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/code.devspoon.com/chain.pem;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

평가: OCSP 스테이플링으로 SSL 핸드셰이크 성능 향상 Cloudflare (1.1.1.1)와 Google (8.8.8.8) DNS 리졸버 사용 OCSP 경고에 대한 유용한 주석 포함


1.5 프록시 설정

샘플 설정 - 기본:

location / {
    autoindex off;
    proxy_pass http://appname:serviceport;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
}

운영 설정 - 포괄적:

location / {
    proxy_pass http://code-server:8443;

    # WebSocket 지원
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    # 완전한 프록시 헤더
    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;

    # 최적화된 타임아웃
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;

    # 버퍼 설정
    proxy_buffering off;
    proxy_request_buffering off;

    proxy_set_header Accept-Encoding gzip;
}

평가: WebSocket 지원 (code-server에 필수) 포괄적인 forwarded 헤더 적절한 타임아웃 설정 대화형 애플리케이션에 최적화된 버퍼 설정 ⚠️ 샘플에는 WebSocket 지원이 완전히 없음


1.6 정적 파일 처리

샘플 설정 - 존재:

location /media {
    autoindex off;
    gzip_static on;
    expires max;
    alias /www/webroot/media;
}

location /static {
    autoindex off;
    gzip_static on;
    expires max;
    alias /www/webroot/static;
}

운영 설정 - 누락:

  • /media 또는 /static location 없음

평가: ⚠️ 누락 - 애플리케이션이 정적 파일을 제공하는 경우 https.conf에 추가해야 함 code-server의 경우, 내부적으로 정적 파일을 처리하므로 의도적일 수 있음 ⚠️ 권장사항: Django/Flask 백엔드를 추가하는 경우 정적 파일 location 포함


1.7 Let's Encrypt ACME 챌린지

샘플 설정:

location ^~ /.well-known/acme-challenge/ {
    allow all;
    root /www/webroot;
}

운영 설정:

location ^~ /.well-known/acme-challenge/ {
    allow all;
    root /www/certbot;
    try_files $uri =404;  # 보안 추가
}

평가: 운영 설정에 try_files $uri =404 추가 - 디렉토리 순회 방지 전용 /www/certbot 디렉토리 사용


1.8 보안 블록 Location

샘플 설정:

location ~ /\. {
    deny all;
}

location ~* \.(log|binary|pem|enc|crt|conf|cnf|sql|sh|key|yml|lock)$ {
    deny all;
}

location ~* (composer\.json|...) {
    deny all;
}

운영 설정 - 향상됨:

location ~ /\. {
    deny all;
    access_log off;  # 차단된 시도는 로그에 남기지 않음
    log_not_found off;
}

location ~* \.(log|binary|pem|enc|crt|conf|cnf|sql|sh|key|yml|lock)$ {
    deny all;
    access_log off;
    log_not_found off;
}

location ~* (composer\.json|...) {
    deny all;
    access_log off;
    log_not_found off;
}

평가: 운영 설정에서 차단된 요청에 대한 로깅 비활성화 - 로그 노이즈 감소 스캐너 시도를 로그에 남기지 않아 성능 향상


2. https.conf에 누락된 운영 준비 기능

2.1 속도 제한 - 누락

권장사항: 추가

# http 블록 또는 server 블록에 추가
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;

# location 블록에
location / {
    limit_req zone=general burst=20 nodelay;
    limit_conn addr 10;
    ...
}

영향: DDoS 및 무차별 대입 공격으로부터 보호


2.2 클라이언트 본문 크기 제한 - 누락

권장사항: 추가

client_max_body_size 10M;  # 애플리케이션 요구사항에 따라 조정
client_body_buffer_size 128k;
client_body_timeout 60s;

영향: 메모리 고갈 공격 방지


2.3 연결 제한 - 누락

권장사항: 추가

keepalive_timeout 65;
keepalive_requests 100;
send_timeout 60s;

영향: 더 나은 리소스 관리


2.4 Gzip 압축 - 누락

권장사항: 추가

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
gzip_disable "msie6";

영향: 대역폭 사용량을 크게 감소


2.5 오류 페이지 - 누락

권장사항: 추가

error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;

location = /404.html {
    internal;
    root /www/error_pages;
}

location = /50x.html {
    internal;
    root /www/error_pages;
}

영향: 더 나은 사용자 경험 및 정보 노출 방지


2.6 요청 메서드 제한 - 누락

권장사항: 추가

location / {
    limit_except GET POST HEAD OPTIONS {
        deny all;
    }
    ...
}

영향: HTTP 동사 변조 공격 방지


2.7 버전 정보 숨김 - 누락

권장사항: 추가 (http 블록에)

server_tokens off;
more_clear_headers 'Server';
more_clear_headers 'X-Powered-By';

영향: 정보 노출 감소


3. SSL/TLS 모범 사례 검증

현재 설정 평가:

설정 현재 값 상태 권장사항
ssl_protocols TLSv1.2 TLSv1.3 올바름 현재 유지
ssl_prefer_server_ciphers off 올바름 유지 (TLSv1.3 모범 사례)
ssl_session_cache shared:SSL:20m 좋음 트래픽이 많으면 50m 고려
ssl_session_timeout 10m 좋음 현재 유지
ssl_session_tickets off 올바름 유지 (더 나은 보안)
ssl_stapling on 올바름 현재 유지
ssl_dhparam 4096-bit 우수 현재 유지
HSTS max-age 31536000 올바름 유지 (1년)

4. 성능 최적화 격차

4.1 캐싱 헤더 누락

권장사항: 추가

location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    access_log off;
}

4.2 열린 파일 캐시 누락

권장사항: 추가

open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;

5. 로깅 개선

현재 설정:

access_log /log/nginx/code.devspoon.com.nginx.log main;
error_log  /log/nginx/code.devspoon.com.nginx_error.log warn;

권장사항:

# I/O 감소를 위한 버퍼 추가
access_log /log/nginx/code.devspoon.com.nginx.log main buffer=32k flush=5s;
error_log  /log/nginx/code.devspoon.com.nginx_error.log warn;

# 더 많은 세부 정보를 포함한 로그 형식 추가
log_format detailed '$remote_addr - $remote_user [$time_local] '
                   '"$request" $status $body_bytes_sent '
                   '"$http_referer" "$http_user_agent" '
                   '$request_time $upstream_response_time '
                   '$upstream_addr $upstream_status';

6. 권장 최종 설정 구조

# HTTP 블록 (포트 80)
server {
    listen 80;
    server_name code.devspoon.com www.code.devspoon.com;

    # 호스트 검증
    if ($host !~* ^(code\.devspoon\.com|www\.code\.devspoon\.com)$) {
        return 444;
    }

    # ACME 챌린지
    location ^~ /.well-known/acme-challenge/ {
        allow all;
        root /www/certbot;
        try_files $uri =404;
    }

    # HTTPS로 리다이렉트
    location / {
        return 301 https://$server_name$request_uri;
    }
}

# HTTPS 블록 (포트 443)
server {
    listen 443 ssl;
    http2 on;
    server_name code.devspoon.com www.code.devspoon.com;

    # SSL 인증서
    ssl_certificate /etc/letsencrypt/live/code.devspoon.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/code.devspoon.com/privkey.pem;
    ssl_dhparam /etc/ssl/certs/code.devspoon.com/dhparam.pem;

    # 최신 SSL 설정
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_ecdh_curve secp384r1;

    # OCSP 스테이플링
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/code.devspoon.com/chain.pem;
    resolver 1.1.1.1 8.8.8.8 valid=300s;
    resolver_timeout 5s;

    # 보안 헤더
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Frame-Options DENY always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss: ws:;" always;

    # 신규: 보안 설정
    server_tokens off;
    client_max_body_size 10M;
    client_body_buffer_size 128k;
    client_body_timeout 60s;

    # 신규: 성능 설정
    keepalive_timeout 65;
    keepalive_requests 100;
    send_timeout 60s;

    # 신규: Gzip 압축
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss;

    # 신규: 파일 캐시
    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

    # 버퍼링을 사용한 로깅
    access_log /log/nginx/code.devspoon.com.nginx.log main buffer=32k flush=5s;
    error_log /log/nginx/code.devspoon.com.nginx_error.log warn;

    # 호스트 검증
    if ($host !~* ^(code\.devspoon\.com|www\.code\.devspoon\.com)$) {
        return 444;
    }

    # 나쁜 봇 차단
    if ($bad_bot) {
        return 403;
    }

    # 메인 애플리케이션
    location / {
        # 신규: 속도 제한
        limit_req zone=general burst=20 nodelay;
        limit_conn addr 10;

        # 신규: 메서드 제한
        limit_except GET POST HEAD OPTIONS {
            deny all;
        }

        proxy_pass http://code-server:8443;

        # WebSocket 지원
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # 프록시 헤더
        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;

        # 타임아웃
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        # 버퍼 설정
        proxy_buffering off;
        proxy_request_buffering off;
        proxy_set_header Accept-Encoding gzip;
    }

    # ACME 챌린지
    location ^~ /.well-known/acme-challenge/ {
        allow all;
        root /www/certbot;
        try_files $uri =404;
    }

    # 신규: 정적 파일 캐싱 (필요시)
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # 닷 파일 차단
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    # 민감한 파일 차단
    location ~* \.(log|binary|pem|enc|crt|conf|cnf|sql|sh|key|yml|lock)$ {
        deny all;
        access_log off;
        log_not_found off;
    }

    # 민감한 설정 파일 차단
    location ~* (composer\.json|composer\.lock|composer\.phar|contributing\.md|license\.txt|readme\.rst|readme\.md|readme\.txt|copyright|artisan|gulpfile\.js|package\.json|phpunit\.xml|access_log|error_log|gruntfile\.js)$ {
        deny all;
        access_log off;
        log_not_found off;
    }

    # 파비콘 및 robots
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        log_not_found off;
        access_log off;
        allow all;
    }
}

7. 우선순위 실행 항목

긴급 (즉시 구현)

  1. 이미 존재: 보안 헤더 (HSTS, CSP 등)
  2. 이미 존재: OCSP 스테이플링
  3. ⚠️ 추가: 속도 제한 설정
  4. ⚠️ 추가: server_tokens off
  5. ⚠️ 추가: client_max_body_size 제한

높은 우선순위 (권장)

  1. ⚠️ 추가: Gzip 압축
  2. ⚠️ 추가: 열린 파일 캐시
  3. ⚠️ 추가: 오류 페이지 처리
  4. ⚠️ 추가: HTTP 메서드 제한
  5. ⚠️ 추가: 로깅 버퍼 설정

중간 우선순위 (선택 사항)

  1. ⚠️ 추가: 정적 파일 캐싱 헤더
  2. ⚠️ 고려: SSL 세션 캐시 크기 증가
  3. ⚠️ 고려: 향상된 로깅 형식
  4. ⚠️ 검토: 특정 애플리케이션 요구사항에 맞는 CSP 정책

8. 설정 의존성

nginx.conf (http 블록)에 필요:

# 서버 블록 전에 정의되어야 함
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;

# 나쁜 봇 탐지 맵
map $http_user_agent $bad_bot {
    default 0;
    ~*malicious 1;
    ~*scrapy 1;
    ~*bot 1;
    ~*crawler 1;
}

# WebSocket 업그레이드 맵
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

# 로그 형식
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for"';

9. SSL/TLS 테스트 권장사항

변경 사항 구현 후 다음으로 테스트:

  1. SSL Labs: https://www.ssllabs.com/ssltest/

    • 목표 등급: A+
  2. Mozilla Observatory: https://observatory.mozilla.org/

    • 목표 점수: A+ 또는 100+
  3. Security Headers: https://securityheaders.com/

    • 목표 등급: A+
  4. OpenSSL CLI:

    openssl s_client -connect code.devspoon.com:443 -tls1_2
    openssl s_client -connect code.devspoon.com:443 -tls1_3
    

10. 요약

https.conf에서 이미 우수한 점:

최신 SSL/TLS 설정 포괄적인 보안 헤더 OCSP 스테이플링 WebSocket 지원 적절한 ACME 챌린지 처리 향상된 프록시 설정 로깅 최적화가 적용된 보안 블록 location

추가해야 할 사항:

⚠️ 속도 제한 ⚠️ 클라이언트 본문 크기 제한 ⚠️ Gzip 압축 ⚠️ 열린 파일 캐시 ⚠️ 서버 토큰 숨김 ⚠️ 오류 페이지 처리 ⚠️ HTTP 메서드 제한

결론:

https.conf는 sample_nginx_https.conf보다 훨씬 우수하며 최신 모범 사례를 따릅니다. 샘플 파일은 구식이고 중요한 보안 기능이 누락되어 있습니다. 위의 권장 추가 사항을 적용하면 https.conf는 운영 등급의 엔터프라이즈 준비 nginx 설정이 될 것입니다.


11. 다음 단계

  1. 긴급 우선순위 항목 검토 및 구현
  2. 설정 테스트: nginx -t
  3. 변경 사항 적용 전 현재 설정 백업
  4. 변경 사항을 점진적으로 적용
  5. 문제가 있는지 로그 모니터링
  6. A+ 등급 확인을 위한 SSL/TLS 테스트 실행
  7. 속도 제한 및 성능 메트릭 모니터링 설정

보고서 생성: sample_nginx_https.conf vs https.conf 비교 기반 기준선: https.conf (code.devspoon.com의 운영 설정) 평가: 권장 개선 사항을 포함한 운영 준비 완료