Nginx 보안 모범 사례: 웹 서버 보호

필수 보안 모범 사례로 Nginx 웹 서버를 보호하세요. 이 가이드에서는 SSL/TLS 연결 보안, 악용 방지를 위한 효과적인 속도 제한 구현, XSS 및 SQL 삽입과 같은 일반적인 웹 공격 완화, Nginx를 최신 상태로 유지하는 것의 중요성에 대해 다룹니다. 서버 보안을 강화하고 온라인 입지를 보호하기 위한 실행 가능한 단계와 구성 예제를 알아보세요.

Nginx 보안 모범 사례: 웹 서버 보호하기

Nginx 서버는 사용자와 공격자가 가장 먼저 접근할 수 있는 공개 서비스인 경우가 많습니다. 이 Nginx 보안 모범 사례는 Nginx가 실제로 적용할 수 있는 제어(TLS, 요청 제한, 헤더, 접근 규칙, 더 안전한 기본값, 정기 업데이트)에 중점을 둡니다.

Nginx는 취약한 애플리케이션 코드 자체를 수정할 수 없습니다. 앱, 데이터베이스, 인증 시스템, 호스트 방화벽 앞에 있는 하나의 계층으로 취급하세요.

TLS로 연결 보안

TLS는 브라우저와 서버 간의 트래픽을 암호화합니다. 신뢰할 수 있는 인증서를 사용하고, HTTP를 HTTPS로 리디렉션하며, 오래된 프로토콜 버전을 비활성화하세요.

인증서 받기

Let's Encrypt는 공개 웹사이트에 일반적이지만, 신뢰할 수 있는 인증 기관이라면 모두 작동합니다. 많은 Linux 서버에서 Certbot은 파일을 /etc/letsencrypt/live/your_domain.com/에 저장합니다.

HTTPS 구성

도메인의 서버 블록을 편집하세요. 경로는 Debian/Ubuntu에서 /etc/nginx/sites-available/, RHEL 계열 시스템에서 /etc/nginx/conf.d/인 경우가 많습니다.

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;

    server_name your_domain.com www.your_domain.com;

    ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;

    # 공유 TLS 설정 포함
    include /etc/nginx/snippets/ssl-params.conf;

    # ... 기타 구성 (root, location 블록 등)
}

server {
    listen 80;
    listen [::]:80;
    server_name your_domain.com www.your_domain.com;

    # HTTP를 HTTPS로 리디렉션
    return 301 https://$host$request_uri;
}

보수적인 TLS 매개변수 사용

공유 TLS 설정을 /etc/nginx/snippets/ssl-params.conf 같은 스니펫에 보관할 수 있습니다.

# /etc/nginx/snippets/ssl-params.conf

ssl_protocols TLSv1.2 TLSv1.3;
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;

# HSTS(HTTP Strict Transport Security) 활성화
# 해당되는 경우 includeSubDomains 추가
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# 더 빠른 인증서 확인을 위해 OCSP Stapling 활성화
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

# Diffie-Hellman 매개변수 (필요시 강력한 매개변수 생성)
# ssl_dhparam /etc/nginx/ssl/dhparams.pem;

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;

모든 하위 도메인이 HTTPS를 지원한다는 것을 확인한 후에만 HSTS에 includeSubDomains 또는 preload를 추가하세요. 잘못된 HSTS 배포는 사용자를 오래된 하위 도메인에서 차단할 수 있습니다.

속도 제한 구현

속도 제한은 무차별 대입 시도, 스크래핑, 우발적인 요청 홍수를 늦추는 데 도움이 됩니다. 완전한 DDoS 솔루션은 아니지만, 앱에 더 많은 숨통을 틔워줍니다.

기본 속도 제한 예제

limit_req_zone은 공유 상태를 정의하고, limit_req는 위치에 제한을 적용합니다.

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;

    server {
        # ...

        location /login {
            limit_req zone=mylimit burst=10 nodelay;
            # ... 로그인 핸들러 구성
        }

        location / {
            limit_req zone=mylimit burst=20 nodelay;
            # ... 메인 사이트 구성
        }
    }
}

이 예제에서: $binary_remote_addr은 클라이언트 IP 주소로 제한을 키잉합니다. burst=10은 평균 속도 이상의 짧은 버스트를 허용하고, nodelay는 초과 요청을 지연시키지 않고 거부합니다.

로드 밸런서나 CDN 뒤에서는 주의하세요. Nginx가 프록시의 IP 주소만 보는 경우, $binary_remote_addr로 속도 제한을 하면 모든 사용자를 하나의 클라이언트로 처벌할 수 있습니다. 클라이언트별 제한에 의존하기 전에 신뢰할 수 있는 실제 IP 처리를 구성하세요.

일반적인 공격 표면 줄이기

Nginx는 노출을 줄일 수 있지만, 애플리케이션은 여전히 입력 검증, 출력 인코딩, 매개변수화된 SQL, 인증 확인, 종속성 패치가 필요합니다.

보안 헤더 추가

보안 헤더는 브라우저 측 위험을 줄일 수 있습니다:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

콘텐츠 보안 정책은 XSS에 도움이 될 수 있지만, 앱의 스크립트, 스타일, 이미지, 타사 서비스와 일치해야 합니다. 프로덕션 사이트에 적용하기 전에 보고 전용 모드로 시작하세요.

눈에 띄는 스캐너 신중하게 차단

간단한 패턴 차단은 시끄러운 스캐너를 막을 수 있지만, WAF를 대체하지는 않습니다. 합법적인 사용자를 차단하지 않도록 좁게 유지하세요.

http {
    # 악성 봇/스캐너 차단을 위한 맵 정의
    map $http_user_agent $bad_bot {
        default 0;
        "~*malicious_bot_pattern" 1;
        "~*another_suspicious_agent" 1;
    }

    server {
        # ...
        if ($bad_bot) {
            return 403;
        }
        # ...
    }
}

민감한 경로 제한

try_files를 사용하고, 디렉토리 목록이 필요하지 않으면 autoindex를 끄고, 제공되어서는 안 되는 숨김 파일에 대한 접근을 거부하세요.

location / {
    root /var/www/html;
    index index.html index.htm;
    try_files $uri $uri/ =404;
    autoindex off; # 디렉토리 목록 비활성화
}

# 민감한 파일 접근 제한 예제
location ~ /\.ht {
    deny all;
}

Nginx 버전 숨기기

server_tokens off는 생성된 오류 페이지에서 Nginx 버전을 제거하고 Server 응답 헤더의 세부 정보를 줄입니다.

http {
    server_tokens off;
    # ...
}

적절한 HTTP 메서드 제한

엔드포인트가 GETPOST만 허용하는 경우, 다른 메서드는 해당 위치에서 거부하세요. CORS 사전 요청이나 PUT, PATCH, DELETE를 합법적으로 사용하는 API 엔드포인트를 깨뜨리지 않도록 위치별로 수행하세요.

location /api/ {
    # GET과 POST만 허용
    if ($request_method !~ ^(GET|POST)$) {
        return 405;
    }
    # ...
}

Nginx 업데이트 유지

보안 수정 사항은 종종 Linux 배포판의 패키지 저장소를 통해 제공됩니다. Nginx와 OpenSSL 관련 패키지를 패치 상태로 유지하고, 업데이트 후 리로드를 테스트하세요.

Debian/Ubuntu:

sudo apt update
sudo apt upgrade nginx

CentOS/RHEL:

sudo dnf update nginx

여전히 yum을 사용하는 오래된 RHEL/CentOS 릴리스에서는 yum update nginx를 사용하세요.

호스트 수준 보호 추가

Nginx 보안은 주변 호스트에도 의존합니다:

  • ufw, firewalld, 클라우드 보안 그룹, 네트워크 ACL에서 필요한 포트만 허용하세요.
  • /var/log/nginx/access.log/var/log/nginx/error.log에서 급증, 반복되는 401/403 응답, 의심스러운 경로를 모니터링하세요.
  • 로그 패턴이 악성 클라이언트를 식별할 수 있는 경우 Fail2ban 또는 유사한 도구를 사용하세요.
  • 각 리로드 전에 sudo nginx -t를 실행하여 보안 변경으로 사이트가 오프라인이 되지 않도록 하세요.

결론

HTTPS, 업데이트, 제한된 포트, 안전한 헤더, /login 같은 민감한 경로에 대한 속도 제한으로 시작하세요. 그런 다음 정기적으로 로그를 검토하세요. 대부분의 Nginx 보안 성과는 다른 사이트에서 복사한 하나의 큰 강화 파일이 아니라, 꾸준한 유지 관리와 명확한 구성에서 비롯됩니다.