「nginxを立ち上げたはいいけど、セキュリティ設定はデフォルトのままで大丈夫なのか不安…」そんな疑問を持つインフラエンジニアは少なくありません。
nginxのデフォルト設定は「とにかく動く」ことを優先した最小構成です。バージョン情報がレスポンスヘッダーに丸見えだったり、HTTPSへのリダイレクトが設定されていなかったりと、攻撃者にとって都合のいい状態のまま公開されているサーバーが現場では多く存在します。
この記事では、Linuxサーバーで稼働するnginxを「攻撃者の視点」で検証し、バージョン情報の隠蔽・HTTPS強制リダイレクト・セキュリティヘッダー・レート制限・バッファ制限まで、現場で即日使える設定方法を解説します。コマンドと設定ファイルの具体的な記述例を中心に構成しているため、手順を追えば1時間以内に基本的な堅牢化を完了できます。

nginxのデフォルト設定が抱えるセキュリティリスク
nginxはApacheと並ぶ代表的なWebサーバーソフトウェアです。軽量・高速で設定の柔軟性が高く、多くの企業のWebサーバーやリバースプロキシとして採用されています。
しかし、「インストールしてすぐ動く」という利便性の裏側に、見落とされがちなリスクが潜んでいます。
・バージョン情報の露出: デフォルトでレスポンスヘッダーにnginxのバージョン番号が含まれ、攻撃者が既知の脆弱性を特定する手掛かりになる
・HTTP通信の放置: HTTPSが設定されていないと、通信内容が盗聴・改ざんされるリスクがある
・セキュリティヘッダーの欠如: クリックジャッキングやXSSを助長する設定のままになっている
・レート制限なし: ブルートフォース攻撃や自動スキャンを無制限に受け付けてしまう
・バッファ設定の甘さ: スローロリス等のスロー系DoS攻撃に対して脆弱になる
これらは「後でやろう」と先送りされがちです。しかし、サーバーを公開した瞬間から攻撃者のスキャンにさらされるのがインターネットの実態です。
攻撃者が狙うnginxの弱点を知る
1. バージョン情報からの脆弱性特定
Server: nginx/1.18.0のようなレスポンスヘッダーが返ってくると、攻撃者はそのバージョンに対応する既知のCVEを即座に調べられます。これはOSINT(公開情報収集)の典型的な手口であり、情報を隠すだけで攻撃のハードルを上げることができます。スキャンツールは1秒以内にバージョンを記録し、攻撃リストに追加します。
2. HTTP通信を狙った盗聴・中間者攻撃
HTTPSが設定されていないサーバーは、通信経路上での盗聴や中間者攻撃(MITM)のリスクを抱えます。「社内ネットワークだから安全」という考えは今日では通用しません。ネットワーク内部への侵入を前提とした「ゼロトラスト」の考え方が現代の標準となっています。
3. セキュリティヘッダー欠如によるブラウザ攻撃
X-Frame-OptionsやContent-Security-Policyといったセキュリティヘッダーが設定されていないと、攻撃者がnginxのページをiframeで埋め込むクリックジャッキングや、スクリプトを挿入するXSS攻撃の踏み台として利用されるリスクがあります。これらはWebサーバー単体の設定で対処できます。
4. レート制限なしによる自動攻撃
レート制限のないサーバーは、ログイン画面への自動的なパスワード総当たり(ブルートフォース)攻撃や、脆弱なエンドポイントを探す自動スキャナーを無制限に受け付けます。攻撃者は数万のリクエストを自動で送信でき、管理者が気づいた時にはアカウント侵害が完了していることもあります。
具体的な防御手順
1. バージョン情報を隠蔽する(server_tokens off)
設定ファイル(通常は/etc/nginx/nginx.conf)のhttpブロックにserver_tokens off;を追加します。
# /etc/nginx/nginx.conf の http ブロック内に追加 http { server_tokens off; # バージョン情報をレスポンスヘッダーから除去 # ... 以下省略 }
設定変更後は、構文チェックと設定の再読み込みを行います。
# 構文チェック(エラーがなければ "test is successful" と表示される) nginx -t # 問題なければ設定を再読み込み(サービス停止なし) systemctl reload nginx # 確認: Server ヘッダーが "nginx" だけになっていればOK curl -I https://yourdomain.example.com/
変更前はServer: nginx/1.18.0のように表示されていたものが、変更後はServer: nginxのみになります。たった1行の変更ですが、スクリプトによる自動スキャンの多くはバージョンを手掛かりにするため、情報を削るだけでリスクを下げる効果があります。
2. HTTPSへ強制リダイレクトを設定する
Let’s Encrypt等でSSL証明書を取得済みの場合、HTTP(ポート80)へのアクセスをHTTPS(ポート443)へリダイレクトします。
# /etc/nginx/sites-available/yourdomain.conf # HTTPアクセスをHTTPSへリダイレクト server { listen 80; listen [::]:80; server_name yourdomain.example.com; # 301リダイレクト(恒久的)でHTTPSへ転送 return 301 https://$host$request_uri; } # HTTPS設定 server { listen 443 ssl; listen [::]:443 ssl; server_name yourdomain.example.com; ssl_certificate /etc/letsencrypt/live/yourdomain.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.example.com/privkey.pem; # TLSバージョン制限(TLS 1.2以上のみ許可・1.0/1.1は無効化) 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; ssl_prefer_server_ciphers off; # セッションキャッシュ(パフォーマンス改善) ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; # ... ルート設定など続く }
ssl_protocolsでTLS 1.2と1.3のみを許可することで、古くて脆弱なSSL/TLS 1.0・1.1を無効化できます。ssl_prefer_server_ciphers off;はTLS 1.3の推奨設定で、クライアント側の暗号スイート選択を優先します。
3. セキュリティヘッダーを追加する
HTTPSのサーバーブロック内に、ブラウザのセキュリティ機能を有効化するヘッダーを追加します。
server { # ... SSL設定の続き # クリックジャッキング対策(iframeへの埋め込みを同一オリジンのみ許可) add_header X-Frame-Options "SAMEORIGIN" always; # MIMEスニッフィング防止(ブラウザがContent-Typeを勝手に変更するのを防ぐ) add_header X-Content-Type-Options "nosniff" always; # HTTPS強制(HSTSヘッダー): 1年間HTTPSを強制、サブドメインにも適用 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # リファラー情報の制限(外部サイトへのURL漏洩を防ぐ) add_header Referrer-Policy "strict-origin-when-cross-origin" always; # 権限の制限(カメラ・マイク・位置情報へのアクセスを拒否) add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; # コンテンツセキュリティポリシー(サイト構成に合わせて調整が必要) # まずは Report-Only モードでテストしてから本番適用する # add_header Content-Security-Policy-Report-Only "default-src 'self';" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always; # ... ルート設定など }
alwaysキーワードを付けることで、エラーレスポンス(4xx・5xx)にもヘッダーが付与されます。これを省略すると、エラーページを通じた攻撃でヘッダーが効かないケースが生じます。
重要な注意点: Content-Security-Policyはサイトの構成(外部CDN・フォント・スクリプトの利用有無)によって設定が大きく変わります。まずはContent-Security-Policy-Report-Onlyヘッダーで影響を確認してから本番適用することを強く推奨します。セキュリティヘッダー全般の詳細については、セキュリティヘッダー完全ガイドもあわせてご覧ください。
4. レート制限でブルートフォース攻撃を防ぐ
limit_req_zoneディレクティブを使って、接続元IPアドレスごとのリクエスト数を制限します。
# /etc/nginx/nginx.conf の http ブロック内 http { # IPアドレスごとに10MB共有メモリを確保し、1秒に10リクエストを上限に設定 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; # ログイン系エンドポイント用: より厳しい制限(1秒1リクエスト) limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r/s; # 制限超過時のログレベルを調整(デフォルトのerrorから変更してログを見やすくする) limit_req_log_level warn; }
# サーバーブロック内 server { # サイト全体にレート制限を適用 # burst=20: 20リクエストまでのバースト(一時的な超過)を許容 # nodelay: バースト内のリクエストも遅延なしに処理 limit_req zone=req_limit burst=20 nodelay; # ログイン画面には厳しい制限 location /login { limit_req zone=login_limit burst=5 nodelay; # 制限超過時は429(Too Many Requests)を返す limit_req_status 429; # ... プロキシ設定など } }
burst=20は「通常の上限を一時的に超えた20リクエストまでは許容する」という設定です。これにより、正規ユーザーが複数のリソースを短時間に読み込んでも制限に引っかかりにくくなります。
nginxのレート制限と並行して、fail2banを組み合わせるとより堅牢になります。nginxのアクセスログを解析してfail2banが自動的にIPをブロックする構成は、現場で広く採用されています。
5. バッファサイズとタイムアウトを制限する
スローロリス(Slowloris)やHTTPフラッド等のDoS攻撃に備え、バッファサイズとタイムアウト値を適切に設定します。
# /etc/nginx/nginx.conf の http ブロック内 http { # クライアントリクエストボディの最大サイズ # ファイルアップロードがある場合は適宜増やす client_max_body_size 1m; # ヘッダーのバッファサイズ制限(デフォルトより小さく設定) client_header_buffer_size 1k; large_client_header_buffers 4 8k; # タイムアウト設定(スローロリス攻撃対策) client_body_timeout 10s; # リクエストボディ送信タイムアウト(デフォルト60s) client_header_timeout 10s; # ヘッダー送信タイムアウト(デフォルト60s) keepalive_timeout 65s; # Keepalive接続のタイムアウト(デフォルト75s) send_timeout 10s; # レスポンス送信タイムアウト(デフォルト60s) # 接続数の制限(DoS対策) limit_conn_zone $binary_remote_addr zone=conn_limit:10m; limit_conn conn_limit 20; # 1IPからの同時接続数を20に制限 }
スローロリス攻撃は、HTTPリクエストを意図的にゆっくり送信することでサーバーの接続リソースを枯渇させる手法です。client_header_timeoutとclient_body_timeoutをデフォルト(60秒)から短く設定することで、この攻撃への耐性を高めることができます。
中小企業でも今日からできること
フルセットで設定するのが難しい場合でも、以下の優先順位で取り組むと効果的です。
・まず「server_tokens off」から: 設定1行で完了し、再起動不要のreloadで反映できる。バージョン情報を隠すだけで、自動スキャンによる大半のターゲティングを回避できる
・次にHTTPS化: Let’s Encryptは無料で取得可能。Certbotを使えば設定もほぼ自動化できる。HTTP→HTTPSリダイレクトも合わせて設定する
・セキュリティヘッダーはテンプレートから始める: Mozilla SSL Configuration Generatorを使えば、サイト構成に合わせた推奨設定を生成できる。CSPは最初はReport-Onlyモードで影響を確認してから本番適用する
・レート制限はログイン画面から: サイト全体への適用は影響が読みにくいので、まずログインや管理画面等のセンシティブなエンドポイントだけ先に設定する
すでにLinuxサーバーの初期セキュリティ設定を済ませている場合、nginxの設定がちょうど次のステップです。OS層のセキュリティを固めたら、アプリケーション層(Webサーバー)のセキュリティを強化することで多層防御が完成します。
Linuxのファイル権限やユーザー管理といった基礎については、姉妹サイトLinuxMaster.JPで詳しく解説しています。サーバー管理の基礎から体系的に学びたい方はあわせてご覧ください。
よくある誤解と注意点
【誤解1】「HTTPSにすれば万全」
HTTPSはあくまで通信経路の暗号化です。アプリケーション層の脆弱性(SQLインジェクション、XSSなど)はHTTPS化だけでは防げません。セキュリティヘッダーの設定やWAFとの組み合わせが必要で、nginxの設定はその一部にすぎません。「100%安全」はどんな設定の組み合わせでも実現できないことを前提に、リスクを下げ続ける姿勢が重要です。
【誤解2】「CSPを設定したらサイトが壊れた」
Content-Security-Policyは設定ミスでサイトの機能が損なわれることがあります。特に外部CDNからjQueryやフォントを読み込んでいる場合、CSPのデフォルト設定ではブロックされます。必ずContent-Security-Policy-Report-Onlyヘッダーで事前にテストしてから本番適用してください。ブラウザのDevToolsでCSP違反レポートを確認しながら設定を調整するのが安全なアプローチです。
【誤解3】「レート制限が厳しすぎると正規ユーザーが困る」
burst値を適切に設定すれば、正規の使い方で制限に引っかかることはほとんどありません。まずはアクセスログを分析して、正常なトラフィックパターンを把握してから設定値を決めましょう。制限超過時のステータスコードを503(デフォルト)ではなく429(Too Many Requests)にすると、正規ユーザーに「混雑している」ことを正しく伝えられます。
【注意】設定変更前後の動作確認を必ず行う
nginxの設定変更はnginx -tで構文チェックを行い、systemctl reload nginx(restartではなくreload)で反映させるのが基本です。restartはサービスが瞬断しますが、reloadは既存の接続を維持しながら設定を更新できます。本番サーバーではreloadを使う習慣をつけてください。また、設定変更前には必ず設定ファイルのバックアップを取っておきましょう。

本記事のまとめ
nginxのセキュリティ設定は、以下の5ステップで体系的に進めることができます。
| 設定項目 | 設定内容 | 対策する脅威 |
|---|---|---|
| server_tokens off | バージョン情報の隠蔽 | 脆弱性スキャン・OSINT対策 |
| HTTPS強制リダイレクト | HTTP→HTTPS 301リダイレクト + TLS 1.2以上のみ許可 | 盗聴・中間者攻撃対策 |
| セキュリティヘッダー | X-Frame-Options・CSP・HSTS・Permissions-Policy等 | クリックジャッキング・XSS対策 |
| レート制限 | limit_req_zone でリクエスト数制限 | ブルートフォース・DoS対策 |
| バッファ・タイムアウト制限 | client_body_timeout・client_header_timeout等の短縮 | スローロリス・HTTPフラッド対策 |
デフォルト設定のままで運用し続けることは、攻撃者にとっての「チャンス」を広げることに等しいです。「完璧な設定が整うまで待つ」より、今日できる1ステップから始めることが大切です。設定ファイルの変更前にはバックアップを取り、変更後にはnginx -tと実際のアクセス確認を怠らない習慣をつけてください。
PR
nginxやSSH、PAM設定など、Linuxサーバー管理者が押さえるべきセキュリティ設定を体系的に解説した一冊。本記事で触れた設定項目をさらに深く学びたい方に適しています。
