Nginx セキュリティベストプラクティス:ウェブサーバーを保護する

Nginx ウェブサーバーを、不可欠なセキュリティのベストプラクティスで保護しましょう。このガイドでは、SSL/TLS 接続の保護、不正利用を防ぐための効果的なレートリミットの実装、XSS や SQL インジェクションといった一般的なウェブ攻撃の軽減、そして Nginx を最新の状態に保つことの極めて重要な意味について解説しています。サーバーのセキュリティを強化し、オンラインプレゼンスを保護するための実用的な手順と設定例を学びましょう。

Nginxセキュリティのベストプラクティス:Webサーバーを保護する

Nginxサーバーは、多くの場合、ユーザーと攻撃者の両方が最初に到達できるパブリックサービスです。これらのNginxセキュリティのベストプラクティスは、Nginxが実際に適用できる制御(TLS、リクエスト制限、ヘッダー、アクセスルール、より安全なデフォルト設定、定期的な更新)に焦点を当てています。

Nginxは、脆弱なアプリケーションコードを単独で修正することはできません。アプリ、データベース、認証システム、ホストファイアウォールの前の1つのレイヤーとして扱ってください。

TLSによる安全な接続

TLSは、ブラウザとサーバー間のトラフィックを暗号化します。信頼できる証明書を使用し、HTTPをHTTPSにリダイレクトし、古いプロトコルバージョンを無効にします。

証明書を取得する

Let's Encryptは公開Webサイトでは一般的ですが、信頼できる認証局であればどれでも機能します。多くの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ステープリングを有効にする
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をサポートしていることを確認した後にのみ、includeSubDomainsまたはpreloadをHSTSに追加してください。不適切な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によるレート制限は、すべてのユーザーを1つのクライアントとして罰する可能性があります。クライアントごとの制限に依存する前に、信頼できる実際の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プリフライトリクエストや、PUTPATCHDELETEを正当に使用する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のセキュリティは、その周囲のホストにも依存します:

  • ufwfirewalld、クラウドセキュリティグループ、ネットワークACLで必要なポートのみを許可します。
  • /var/log/nginx/access.log/var/log/nginx/error.logを監視して、スパイク、繰り返される401/403応答、不審なパスを確認します。
  • ログパターンが悪意のあるクライアントを特定できる場合は、Fail2banまたは同様のツールを使用します。
  • リロードする前に毎回sudo nginx -tを実行して、セキュリティ変更がサイトをオフラインにしないようにします。

まとめ

HTTPS、更新、制限されたポート、安全なヘッダー、/loginなどの機密パスへのレート制限から始めてください。その後、定期的にログを確認してください。Nginxのセキュリティ上の利点のほとんどは、他のサイトからコピーされた1つの大きな強化ファイルではなく、安定したメンテナンスと明確な設定からもたらされます。