🔥

Nginxでレスポンスヘッダの一部を隠蔽する方法

2021/02/21に公開

はじめに

拡張モジュールが導入されていないNginxでは、バージョンを隠すことはできますが、Nginxを使っていること自体は隠すことができません。

レスポンスヘッダには使用しているサーバ(Apache/Nginxなど)の他にも色々な情報が載っています。中にはセキュリティ上問題となる情報が含まれていることもあります(例えばApacheではデフォルトの設定だとOpenSSLのバージョンが表示されていたりします)

Nginxはデフォルトの設定のままでもセキュリティ的に大きな問題はないですが、レスポンスヘッダは攻撃者の良い材料ともなり得るので、できるだけ不要な情報は隠すことが望ましいです。

ここでは、Nginxでレスポンスヘッダの情報をできるかぎり隠蔽する方法を説明します。以下の説明では状況に応じてsudoをつけてください。

TL;DR

$ wget https://nginx.org/download/nginx-X.XX.X.tar.gz
$ tar -xzvf nginx-X.XX.X.tar.gz
$ wget https://github.com/openresty/headers-more-nginx-module/archive/vX.XX.tar.gz
$ tar -xzvf vX.XX.tar.gz
$ cd nginx-X.XX.X
$ ./configure --add-dynamic-module=拡張モジュールをインストールしたディレクトリのパス/headers-more-nginx-module-X.XX --with-http_ssl_module --with-http_v2_module
$ make
$ sudo make install

X.XX.XX.XX にはそれぞれ Nginx や 拡張モジュールのバージョンが入る。Nginx のバージョンについては公式サイトのダウンロードページ、拡張モジュールのバージョンについてはGitHubのページを参照のこと。

/usr/local/nginx/conf/nginx.conf
load_module  /usr/local/nginx/modules/ngx_http_headers_more_filter_module.so;

http {
    server_tokens      off;
    more_clear_headers Server;
    more_clear_headers ETag;
    more_clear_headers Transfer-Encoding;
    more_clear_headers Date;
    more_clear_headers Status;
    more_clear_headers X-Request-Id;
    more_clear_headers X-Runtime;
    more_clear_headers X-UA-Compatible;
    more_clear_headers Cache-Control;
    more_clear_headers Connection;
    more_clear_headers X-Powered-By;

    # 以下省略
}
~/.bashrc
export PATH="/usr/local/nginx/sbin:$PATH"
$ source ~/.bashrc
$ sudo visudo
visudo
- Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin
+ Defaults    secure_path = /sbin:/bin:/usr/local/nginx/sbin:/usr/sbin:/usr/bin
$ sudo nginx # すでに起動している場合は $ sudo nginx -s reload

$ curl -I ドメイン名
HTTP/1.1 200 OK
Content-Type: text/html
... # 指定のレスポンスヘッダが隠蔽されていればOK

ソースからビルド

大前提として、Nginxでレスポンスヘッダを編集するには拡張モジュールが必要となります。そしてこの拡張モジュールは、Nginxをソースからビルドして追加する必要があります。

公式サイトからダウンロードします。

$ wget https://nginx.org/download/nginx-X.XX.X.tar.gz

:warning: X.XX.Xの箇所はNginxのバージョンを指定してください。バージョンは公式サイトのダウンロードページから確認できます。Stable version (安定版) か Mainline version (最新版) のどちらかのバージョンを選んでください。

ダウンロードした圧縮ファイルを展開します。

$ tar -xzvf nginx-X.XX.X.tar.gz

次に、レスポンスヘッダを編集するための拡張モジュールをダウンロードします。headers-more-nginx-module を使用します。

$ wget https://github.com/openresty/headers-more-nginx-module/archive/vX.XX.tar.gz

:warning: vX.XX.tar.gzには拡張モジュールの最新版をバージョンを入れてください。最新版のバージョンはGitHubのページから確認できます。たとえば、v0.31.tar.gzのような形式です。

ダウンロードした圧縮ファイルを展開します。

$ tar -xzvf vX.XX.tar.gz

展開したNginxのディレクトリに移動します。

$ cd nginx-X.XX.X

移動したら以下のコマンドを実行します。こちらはSSL/TLS通信(HTTPS通信)を使わない人向けです。

$ ./configure --add-dynamic-module=拡張モジュールをインストールしたディレクトリのパス/headers-more-nginx-module-X.XX

こちらはSSL/TLS通信を使う人向けです。

$ ./configure --add-dynamic-module=拡張モジュールをインストールしたディレクトリのパス/headers-more-nginx-module-X.XX --with-http_ssl_module --with-http_v2_module

HTTP/2を使わない人は--with-http_v2_moduleを外しても良いですが、せっかくSSL/TLS対応しているのであればHTTP/2にも対応したほうがオトクです。

ちなみに上記コマンドでは/usr/local以下にNginxがインストールされます。場所は変更しなくて良いですが、変えたい場合は--prefix=インストールしたいパスを追加してください。ただし別の場所にインストールした場合は、モジュールをあとから追加する際に毎回--prefixオプションを付けなければいけないことに注意してください。なお、以下の説明では/usr/localにインストールされたものとして説明します。

上記コマンドを実行したら続けて以下のコマンドを実行します。

$ make
$ sudo make install

これで/usr/localに、拡張モジュール付きでNginxがインストールされます。ちなみに拡張モジュールは/usr/local/nginx/modules以下に置かれます。

参考: headers-more-nginx-module - GitHub

レスポンスヘッダを隠蔽

Nginxの設定ファイルにレスポンスヘッダを隠す設定を追加していきます。まずは拡張モジュールを読み込まないといけないので、ディレクティブの外({}で囲まれていない外の部分)に以下の一行を追加します。ディレクティブの外ならどこでも良いですが、わかりやすいようにファイルの最初の辺りに書いておくと良いです。

/usr/local/nginx/conf/nginx.conf
load_module  /usr/local/nginx/modules/ngx_http_headers_more_filter_module.so;

:warning: /usr/local以外にインストールした場合は適宜パスを変更してください

次にレスポンスヘッダを隠す設定を追加します。レスポンスヘッダにはサイトによって色々な情報が含まれますので、実際には他にもたくさん設定があります。以下はその一例です。詳しくはリポジトリを参照してください。また、レスポンスヘッダ情報によっては隠してしまうとアプリケーションが正しく機能しなくなる可能性があるので注意してください。Railsではmore_clear_headers Content-Type;を追加するとうまく動きませんでした。適宜、環境に合わせて編集してください。

httpディレクティブ(http { }内のどこか)に以下を追加します。

/usr/local/nginx/conf/nginx.conf
http {
    server_tokens      off;
    more_clear_headers Server;
    more_clear_headers ETag;
    more_clear_headers Transfer-Encoding;
    more_clear_headers Date;
    more_clear_headers Status;
    more_clear_headers X-Request-Id;
    more_clear_headers X-Runtime;
    more_clear_headers X-UA-Compatible;
    more_clear_headers Cache-Control;
    more_clear_headers Connection;
    more_clear_headers X-Powered-By;
    # more_clear_headers Content-Type;

    # 以下省略
}

参考: [Nginx] レスポンスヘッダを限りなく消す

more_clear_headersで各レスポンスヘッダ情報を隠します。server_tokensはNginxのバージョンを表示するかどうかです。なお、server_tokensに関してはソースからビルドしなくても(拡張モジュールを使用しなくても)使用できます。

パスを通す

すでにNginxをyumaptでインストール済みの場合は、nginxコマンドがそちらのパスを参照するようになっていることが多いです。

$ which nginx
/usr/sbin/nginx  # パッケージからインストールしたNginxを参照してしまっている

なので、nginxコマンドを、今回インストールしたほうを使うようにします。既存のNginxを削除すれば、誤って元のNginxを操作してしまう可能性が減ります。

CentOS
# 実行しない!!
$ sudo yum -y remove nginx
Ubuntu
# 実行しない!!
$ sudo apt -y purge nginx

ただし、削除してしまうと一緒に設定ファイル等も削除されてしまうので、設定ファイル等をあらかじめバックアップしておく必要があります。

また、万一ソースからビルドしたNginxでうまくいかない場合、先に既存のNginxを削除してしまうと色々と厄介です。

さらに、既存のNginxを削除したとしてもそのままではパスが通っていないので、結局はパスを通すことになります。

$ which nginx
# パスが見つからない!

なので既存のNginxを削除するのはすべての作業が終わってからでも十分です。

Nginxをすでにインストールしていてもいなくても、パスを通す必要があります。以下のように、$PATHよりも前に/usr/local/nginx/sbinが来るようにパスを設定してください。これは、既存のNginxが参照されてしまうことを避けるためです。

~/.bashrc
export PATH="/usr/local/nginx/sbin:$PATH"

追加したら設定を反映させます。

$ source ~/.bashrc

nginxのパスを確認して、/usr/local/nginx/sbin/nginxとなっていればOKです。

$ which nginx
/usr/local/nginx/sbin/nginx  # OK!

また、nginxコマンドはroot権限で実行することが多いので、sudoをつけたときにも同じようにパスが通るようにする必要があります。以下のコマンドでroot権限での設定を変更します。

$ sudo visudo

vimなどのエディタが立ち上がるので、以下の一行を探してください。

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

:warning: パスはOSによって異なる場合があります。

すでにあるパスに対して元々のNginxがあるパス(/usr/sbin)より前に/usr/local/nginx/sbinを追加します。元々のNginxがなければ(インストールしてなければ)末尾に追加しても問題ないです。

Defaults    secure_path = /sbin:/bin:/usr/local/nginx/sbin:/usr/sbin:/usr/bin

:warning: このファイルはかなり特別なファイルなので、くれぐれもタイプミスをしないように注意してください。特に:を忘れないように!

これでsudoを使ったときでも/usr/local/nginx/sbinにパスが通るようになります。
参考: 【Linux】「sudo: service: command not found」というエラーが出た場合の対処法

Nginxを起動

それではいよいよ起動します。よく使うコマンド一覧です。

$ sudo nginx            # 起動
$ sudo nginx -s reload  # リロード
$ sudo nginx -s stop    # 終了

何もメッセージが表示されなければ起動成功です。

確認

ただサーバが起動しただけではレスポンスヘッダが隠せているかどうかがわからないので、実際に確認してみましょう。ここでは2種類の確認方法を紹介します。

ディベロッパーツールを使用する

Google Chrome を例に紹介します。他のブラウザの場合は各自で調べてみてください。ディベロッパーツールを開くには、WindowsではF12, Macでは command + option + i です。もしくは右クリックの「検証」でも開けます。

ディベロッパーツールを開いたらNetworkタブを開きます。開いたら一度ページをリロードする必要があります。リロードしたら、左側にたくさんのファイル名が出てくると思いますが、一番上(example.comindex.htmlやURLのパス名などになっている)のものをクリックします。

network_information.png

すると以下のように表示されます。

response_headers.png

ここの Response Headers となっている部分がレスポンスヘッダになります。これがサーバからクライアント側に送られるサーバ情報ですね。ここに、Nginxで設定したレスポンスヘッダが表示されていなければ成功です!

cURLを使用する

curlコマンドを使用するとサーバからのレスポンス情報が確認できます。

$ curl -I ドメイン名

:warning: http://でリクエストがあった際にhttps://にリダイレクトするような設定にしている場合は明示的にhttps://と入力する必要があります。

$ curl -I https://noraworld.jp
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 2915
Connection: keep-alive
Cache-Control:
Strict-Transport-Security: max-age=31536000; includeSubDomains;

ブラウザで確認したのと似たような結果が返ってきます。ここにNginxで設定したレスポンスヘッダが表示されていなければOKです!

拡張機能を使用する

これはレスポンスヘッダを確認するわけではないのであくまで参考程度ですが、個人的に好きな拡張機能なのでおまけとして載せておきます。

Wappalyzerを使用すると、そのサイトでどのようなサーバ、アプリケーション等が使われているかが簡単に確認できます。

Google Chrome では Chrome Web Store からインストールできます。

インストールすると拡張機能の欄にアイコンが追加されます。調べたいサイトにアクセスしたときに表示された内容が、そのサイトで使われているサーバやアプリケーションになります。

たとえばQiitaではこんな感じ。

qiita_wappalyzer.png

レスポンスヘッダを確認するというよりは使われているアプリケーションを調べるツールですが、ここにNginxという表記がなければServerは隠せていることになります。また、Expressなどを使用しているサイトではX-Powered-Byを隠すことにより解析できない(表示されない)ようになります。

余談ですが、ここにバージョン等が表示されていたら少し気をつける必要があります。

その他

既存のNginxから設定ファイルをコピーしてきた場合は、パスなどに注意する必要があります。たとえば自分の場合は、SSL/TLS通信で使用するDH鍵(ssl_dhparam)のパスが変わったのに気が付かずにエラーになりました。他にも404エラーページのHTMLのパスなどが変わることがありますので、既存のNginxの設定を引き継ぐ際はご注意ください。

参考サイト

GitHubで編集を提案

Discussion