はじめに
こんな感じで、Hostヘッダのない HTTP1.0通信でIPアドレスが漏れる。
グローバルIPアドレスならいいけど、プライベートIPアドレスだと、少しセキュリティ上の問題になる。
仕組み
- HTTP/1.0 の話
- HTTP/1.0 では Host ヘッダはオプション(あってもなくてもよい)
- まぁ、大抵のWebブラウザでは、HTTP/1.0でもHostヘッダは付けるけど、つけなくてもよい
- 大抵の Web サーバは、仮想ホスト機能に対応している
- Hostヘッダのない HTTP リクエストは、どの仮想ホストに対応させていいか分からない
- しかも、ディレクトリに対して最後の「/」がないという「no TrailingSlash」状態
- Location で再リクエストを要求したいけど、フルパスURLのホスト名が分からない
- しょうがないので、NICのIPアドレスつけちゃえ
という感じ
対策
仮想ホストを設定する
- 運用しているホスト名の仮想ホストの設定をする
- それ以外の既定の設定は、無効にする。
- または空のルートディレクトリだけを用意する
- 全てアクセス禁止にする
とあれば、Host ヘッダのない HTTP リクエストは、既定の設定になり、上記のようなリダイレクトメッセージは送出されなくなる
つまり元々、仮想ホスト機能は、一つの Webサーバで複数のWebサイトを運用するための機能だけど、
一つのWebサイトでもいいジャン・・・そして、既定のWebサイト(設定されたものとは当てはまらなかったホスト名(ホストヘッダ無も含))の設定をエラー/禁止/無意味(空のPublicRoot)にすれば、リダイレクト要求のレスポンスが送出されないようにできる
仮想ホストを設定するのデメリット
- ぶっちゃけ面倒じゃない!?
- DNSが壊れた時、緊急で IPアドレスの URL でアクセスしようとしてもできなくなる
- DNSが壊れた時、Hosts ファイルで名前解決すればアクセスできるけど・・・
上記のデメリットがデメリットでない環境であれば、仮想ホストを設定するのが王道かと思う
Nginx の場合
ググレばいくらでもあると思う
Apache の場合
ググレばいくらでもあると思う
IIS6 の場合
デフォルトだと「ホストヘッダ」の値が空欄なので、なんでも受け付ける
仮想ホストの設定で、「ホストヘッダ」を限定させる
すると、こんな感じになる
Hostヘッダがないと、アクセスできなくなる(Bad Requestになる)
IIS7 の場合
こんな感じで「ホスト名」を空欄から特定値に設定する
Hostヘッダがないと、アクセスできなくなる(Not Foundになる)
仮想ホストを設定する以外の対策
Nginx の場合
設定ファイルの「server_name」を適切に設定し、「server_name_in_redirect on」にする
すると、こんな感じになる。
「server_name_in_redirect on」の弊害
仮想ホスト環境でも、唯一の「server_name」がリダイレクトURLのホスト名になってしまう事だが、そういう環境の場合は、上記の仮想ホストを作る対策(既定は無効なWebサイト)でいいので、そちらにすること。
Apache の場合
設定ファイル(httpd.conf)の「ServerName」ディレクティブを設定する
すると、こんな感じになる。
Apache2.4 系の場合
そもそも 2.4 系列からは、IPアドレスではなくて、「hostname」コマンドで指定された値が返されるようになったらしい。
こんな感じ
「localhost.localdomain」って、CentOS の既定値だな。
それでも、おかしな値を hostname コマンドで指定すると、IPアドレスが出てしまう事もある。
この画面例は IPv6 アドレスだけどね。
IIS の場合
IIS4.0/5.0/5.1の場合、メタベースなど変更
これも、ググってくれ
この設定で、IPアドレスの代わりにコンピュータ名が使われるようになるが、コンピュータ名とNTドメイン名(ActiveDirectoryドメイン名)を工夫すると、コンピュータ名とはいいながら適切な FQDN として出力させる事もできるので、工夫してくれ
IIS の場合 URLScan を使う
IIS の場合 sISAPILocation を使う
昔、ISAPIフィルタ「sISAPILocation」を作った。
これには、特定の値(例えば今回の事象で漏れてしまうプライベートIPアドレス)を、別の値(例えばFQDNの文字列)に書き換える機能があるので、それが使えると思う。
というか、このために作った。
IIS の場合 トレイディングスラッシュの強制
という HttpModule を作ってみた。
これは、「no TrailingSlash」なディレクトリ要求を「TrailingSlash」にして、IISに渡す HttpModuleなので、今回のような事象は発生しないようにしている。
加えて
「no TrailingSlash」→「リダイレクト要求」→「TrailingSlashで再度リクエスト」→「求めていた結果」ではなく、
「no TrailingSlash」→「TrailingSlashにしてIISに渡す」→「求めていた結果」なので、通信上もメリットがあると思う。
IIS の場合(蛇足)
これ以外にも基本認証を有効にしていると IPアドレスが漏れる場合があるので、注意。
リンクと書籍
- apache 2.4 の ServerName
- ServerName ディレクティブ
- 「Apacheクックブック」(ISBN978-4-87311-381-4)
- P189 "レシピ9.1 Hostフィールドがないリクエストを処理する"
- P252 "レシピ13.3 「末尾のスラッシュ」問題を解決する"
- P254 “レシピ13.5 Hostヘッダフィールドがないリクエストを処理する”
- オライリー「マスタリングnginx」(ISBN-13: 978-4873116457)
- nginx はどのようにリクエストを処理するか - サーバ名未定義のリクエストの処理を防ぐ
How to prevent processing requests with undefined server names - NginxによるTrailingSlashのメモ
- Rails + Nginx環境で強制的にURLの最後に / を付ける方法
- 参考 : IIS が HTTP ヘッダー (Content-Location) で IP アドレスを返す
- フィールドには、TCP ヘッダーには、IIS 6.0 で IP アドレスが表示されます。
- Removing an IIS server's IP address from HTTP responses
蛇足
ときどき、全ての正常なページ遷移(リンク)が「no TrailingSlash」な場合があるけど、これは
「no TrailingSlashな要求」→「30x リダイレクト要求」→「TrailingSlashにして再要求」→「求めていた結果」となるので、通信が2往復かかるので、ネットワークに無駄な負荷がかかるので、パフォーマンス上も「no TrailingSlashな要求」はよくないと思う。
今回のメインテーマは、パフォーマンス上もなにも、プライベートIPアドレスが知りたいので、あえて実行しているので、この項の正常なページ遷移とは異なるテーマなんだけど、一応書いておいた。