PR

VPSのセキュリティを段階的に高めていく|Nginxで隠しファイルブロックとセキュリティヘッダーを追加する手順

Nginxで隠しファイル(.env・.git)へのアクセスをブロックし、HSTSなどのセキュリティヘッダーを設定してVPSのセキュリティを強化するイメージイラスト VPS・RentalServer
この記事は約10分で読めます。
記事内に広告が含まれています。
スポンサーリンク

この記事は、「VPSのセキュリティを段階的に高めていく」シリーズの続きとなる記事です。
これまでの記事は、以下のページにまとめていますので、ぜひご一読ください。

今回は、個人運用のVPSに構築したUbuntu Server上の
Nginx環境におけるセキュリティ対策として、
ボットによる自動スキャン攻撃や、
Web特有の脆弱性からサイトを保護するための設定を行います。

具体的には、
「隠しファイル・ディレクトリへのアクセスブロック」と
「HSTSを含む各種セキュリティヘッダーの付与」の2点です。

私が実際に設定を行う中で直面した失敗事例も交えながら、
環境を壊さずに安全に変更を反映させる手順を整理します。

この記事では、以下の手順を分かりやすく解説します。

  • 悪意あるボットから.envや.gitなどの隠しファイルを守る設定方法
  • Let’s Encrypt(Certbot)の自動更新を邪魔しないための例外処理
  • HSTSなどのセキュリティヘッダーを追加して通信の安全性を高める方法
  • Nginxの設定でハマりやすい「ヘッダー上書きの罠」とその回避策
  • 設定変更後に環境を壊さず、安全にテスト・反映させるコマンド

脅威と防御の仕組み(何をどう防ぐのか)

設定ファイルを開く前に、まずは「どのような攻撃があり、それをどう防ぐのか」を簡単に整理しておきます。

隠しファイル(.env / .git等)へのスキャン攻撃

悪意のあるボットは、Webサイトに対して無差別に /.env/.git/config といったファイルの存在を確認するアクセス(スキャン)を行ってきます。
実際に日々のログを確認すると、これらのファイルに対する大量の404エラーが記録されていることがわかります。

もし設定ミス等でこれらのファイルが公開領域に置かれていた場合、データベースのパスワードやAPIキーなどの致命的な機密情報が漏洩してしまいます。

そこでNginxの設定で「ドット(.)から始まるファイルやディレクトリには、問答無用でアクセスを拒否(404 Not Foundを返す)する」というルールを追加します。
これにより、WordPressやPHPの処理に到達する手前で、安全かつ軽量に攻撃を弾き返すことができます。

HTTPダウングレード攻撃とHSTS

サイトをHTTPS化していても、攻撃者が通信経路に割り込み、利用者を強制的に暗号化されていないHTTP通信へ誘導(ダウングレード)して、通信内容を盗聴したり改ざんしたりする中間者攻撃のリスクがあります。

これを防ぐために Strict-Transport-Security (HSTS) というヘッダーを付与します。
これにより、ブラウザに対して「このサイトには今後1年間、必ずHTTPSで接続しなさい」と強制記憶させることができます。

その他のWeb脆弱性と追加セキュリティヘッダー

その他にも、第三者の悪意あるサイトに自分のブログを透明な枠(iframe)で重ねて誤操作を誘う「クリックジャッキング」や、ブラウザがファイルの種類を誤認して悪意あるスクリプトを実行してしまう「MIMEスニッフィング」などの攻撃手法が存在します。

これらを防ぐため、いくつかのセキュリティヘッダーを追加してブラウザの挙動を制限します。

実践:Nginx設定ファイルの編集

ここからは、実際に個別サイトの設定ファイルを編集していきます。

事前準備:正しいバックアップの取り方(失敗事例)

設定を変更する前に、必ず現在の設定ファイルのバックアップを取ります。
ここで私が実際にやってしまった失敗事例を共有します。

設定変更前に /etc/nginx/sites-enabled/ ディレクトリ内でそのままコピーを作成(例: note.bak)したところ、のちほどの構文チェックで conflicting server name(サーバー名が競合している)という警告が発生してしまいました。

原因は、Nginxは sites-enabled/ ディレクトリの中にあるファイルを、拡張子に関わらず全て設定ファイルとして読み込もうとする仕様があるためです。
本番ファイルとバックアップファイルの両方を読み込んでバッティングしてしまったわけです。

バックアップファイルは、Nginxが読み込まない安全な場所(自身のホームディレクトリ ~/ など)に退避させるのが正解です。以下のコマンドでバックアップを作成します。

sudo cp /etc/nginx/sites-enabled/対象ファイル ~/対象ファイル.bak_日付

設定ファイルの編集と追記

バックアップが取れたら、設定ファイルを開きます。

sudo nano /etc/nginx/sites-enabled/対象ファイル

SSL設定が記述されている server ブロック内に、以下の2つの設定ブロックを追記します。

1. 隠しファイルのアクセスブロック設定

    # 隠しファイル・隠しディレクトリへのアクセス禁止 (.env, .git等を含む。ただし .well-known は除く)
    location ~ /\.(?!well-known).* {
        deny all;
        return 404;
    }

ここで初心者が知っておくべき、非常に重要なポイントがあります。

Let’s Encrypt(Certbot)でSSL証明書を自動更新している場合、認証のために /.well-known/acme-challenge/ という一時的な隠しディレクトリが使われます。

単に /\. で全てブロックしてしまうと証明書の更新が失敗してしまうため、(?!well-known) という正規表現を用いて「.well-knownだけはブロックの対象外とする」という例外処理を含めることが必須となります。

注意:バックスラッシュが円マークで表示される場合があります
ターミナル上で設定ファイルを開いた際、隠しファイルを指定する正規表現のバックスラッシュが、円マークとして表示されることがあります。
これはターミナルソフトやWindows環境においてよく発生する、文字コードやフォントに起因する問題です。
ターミナルソフトのフォント設定でConsolasCascadia CodeLucida Console などバックスラッシュに対応したフォントを選べるようでしたら、設定を変更してみてください。

2. セキュリティヘッダーの追加設定

続いて、同じ server ブロック内にセキュリティヘッダーの記述を追記します。

    # セキュリティヘッダーの追加
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

各設定の末尾に always を付けているのは、エラーページ(404など)が表示された際にも確実にヘッダーが出力されるようにし、エラー画面を起点とした隙を塞ぐためです。

追記した各ヘッダーは、具体的に以下のような防御機能を持っています。

  • X-Frame-Options "SAMEORIGIN":自分のサイト以外からiframeで読み込まれるのを防ぎます(クリックジャッキング対策)
  • X-Content-Type-Options "nosniff":ブラウザが勝手にファイル形式を推測して、不正なスクリプトを実行するのを防ぎます(MIMEスニッフィング対策)
  • Strict-Transport-Security:ブラウザに常にHTTPS通信を強制させます(HSTS設定)
  • Referrer-Policy:別サイトへ移動する際、リンク元のURL情報の送信を制限して情報漏洩を防ぎます
  • Permissions-Policy:サイト上でカメラやマイク、位置情報などの機能を無断使用させないようにします

追記が終わったら、ファイルを保存して閉じます。

Nginxの「ヘッダー上書き(継承切断)」の罠

実は当初、これらのセキュリティヘッダーを大元の設定ファイルである /etc/nginx/nginx.conf に追記して全体に適用させようとしました。しかし、設定後に確認してみると、設定したはずのHSTS等のヘッダーが一切出力されていませんでした。

原因は、Nginxの「個別サイトのブロック(server)内に add_header の記述が1行でも存在すると、親ブロック(nginx.confhttp)に書かれた add_header は全て無視される」という非常に強力な上書き(継承切断)の仕様にありました。

私の環境では、個別サイトの設定ファイル内に既存の基本的なヘッダー設定が既に存在していたため、大元のファイルに書いた設定が完全に無効化されていました。

そのため、大元の nginx.conf への追記は取りやめ、今回のように個別サイトの設定ファイル内に、HSTS等を含めた完全版としてまるごと置き換える(統合する)ことで、無事に反映させることができました。

変更を安全に反映・確認する手順

設定を変更した際は、いきなり再起動するのではなく、以下の手順を踏んで安全に確認を行います。

1. 構文チェック(最重要)

文法エラーがないか、必ずテストコマンドを実行します。

sudo nginx -t

syntax is oktest is successful が出れば問題ありません。

2. 設定の再読み込み(リロード)

restart(再起動)ではなく reload(再読み込み)を使うことで、Webサイトを瞬断させずに設定を反映できます。

sudo systemctl reload nginx

3. ヘッダーの反映確認

対象のURLに通信を送り、返ってきたヘッダー情報の中に、設定した項目(Strict-Transport-Security など)が含まれているかを確認します。

curl -I https://対象のURL/

対象のURLは、ご自身のブログなどのトップページのURLを入れてください。

コマンドを実行すると、以下のようにサーバーからの応答(HTTPヘッダー情報)がテキストで返ってきます。

HTTP/1.1 200 OK
Server: nginx
(中略)
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()

出力結果の下半分に注目してください。
今回設定ファイルに追記した5つのセキュリティヘッダー(X-Frame-OptionsStrict-Transport-Security など)がしっかりと表示されていれば、設定は無事にサイトへ反映されています。

4. Certbot(Let’s Encrypt)への影響確認

最後に、隠しファイルのブロック設定が、SSL証明書の自動更新を阻害していないかテスト(シミュレーション)します。

sudo certbot renew --dry-run

対象のドメインで success という結果が出れば、例外処理が正しく働き、今後の証明書更新も問題なく行われることが確認できます。

まとめ

今回は、個人運用VPSのNginx設定ファイルを編集し、隠しファイルへのスキャン対策とセキュリティヘッダーの追加を行いました。

設定自体は数行の追記ですが、「バックアップファイルの置き場所」や「ヘッダーの継承切断」、「Certbotの例外処理」など、Nginx特有の仕様を理解していないと思わぬトラブルを招く部分でもあります。私自身もいくつか失敗を経験しましたが、そのおかげでNginxの挙動への理解が深まりました。

設定変更時は必ず nginx -t で構文チェックを行い、reload で反映させるという基本の手順を守ることで、稼働中のサイトへの影響を最小限に抑えつつ、着実に防御力を高めていくことができます。

コメント

タイトルとURLをコピーしました