IISでServerヘッダを改変/削除する

## Windows の Webサーバとしての IIS

IIS は Vista系列、Windows Server 2008 の IIS7 で大幅な設計変更が行われたようだ(伝聞で不確かです)。

IIS はユーザモードの IIS とカーネルモードの HTTP.SYS に分解され、(静的コンテンツなどの)ディスクキャッシュなどはカーネルモードで処理されるので、高速化されている。

カーネルモードだし、nginxのようなイベントドリブンモデルだし、速い事このうえないだろうと思うんだけど。

旧来の Windows/IIS は脆弱性が多いという印象があると思うけど、Windows/IIS さらには ASP.NET でWebを運用すると、OpenSSL 祭り、Bind 祭り、Struts 祭りなどの脆弱性祭りに参加することはないので、お勧めかもしれない。

## 執筆動機

[.NET FrameworkでServerヘッダを改変するHttpModule](http://rocketeer.dip.jp/sanaki/free/free152.htm)を作ったのだが、マネージドHttpModuleではヌケが出てきてしまうので、注意喚起する意味も込めて、この記事を書いてみた。

## 参照URL

* [【ASP.NET】HTTPレスポンスヘッダーからASP.NET/IISの情報を削除する](https://qiita.com/t_takahari/items/b48db4605adb7e5f818c)
* [IIS の Server ヘッダーを消去する](https://blogs.technet.microsoft.com/jpiis/2017/08/15/iis-server-header-delete/)
* [IIS7 の機能を拡張してみる-レスポンスヘッダー内のサーバー名の改ざん](https://blogs.msdn.microsoft.com/osamum/2010/04/05/iis7-2/)

など、この手の情報は、検索すると多くページがヒットする

## 結論

IIS/ASP.NETの隠蔽には、

* IIS
* HTTP.SYS
* ASP.NETなどのその他

の3つの階層に注目する必要があるのだが、**レジストリ+ネイティブモジュール(UrlRewrite)+その他(ASP.NETの隠蔽)** 一択だと思う。

つまり、参照 URL の「 [【ASP.NET】HTTPレスポンスヘッダーからASP.NET/IISの情報を削除する](https://qiita.com/t_takahari/items/b48db4605adb7e5f818c)」でHTTP.SYSとIISについて「ASP.NETなどについては、[IIS の Server ヘッダーを消去する](https://blogs.technet.microsoft.com/jpiis/2017/08/15/iis-server-header-delete/)」を参照すれば、以下終了だと思う。

## HTTP.SYS

レジストリをいじる

↓を参照してくれ
* [IIS の Server ヘッダーを消去する](https://blogs.technet.microsoft.com/jpiis/2017/08/15/iis-server-header-delete/)

レジストリをいじると、↓のような感じになる

> C:\\>StreamRelay.NET.exe -localport 0 -remotehost 192.0.2.3 -remoteport 80
> aa
> HTTP/1.1 400 Bad Request​
> Content-Type: text/html; charset=us-ascii​
> Date: Mon, 12 Nov 2018 14:05:57 GMT​
> Connection: close​
> Content-Length: 326​

どうも、HTTP的に正しくないメッセージは、HTTP.SYS側で判断してドロップされるようだ(カーネルモードだけで済むということか)。
→ なので、Serverヘッダの改変/削除を確実に実現するには IISの設定だけではなくて、HTTP.SYS側のレジストリの設定も必要になる

## IIS

[マネージドモジュール(System.Web.IHttpModule)](https://msdn.microsoft.com/en-us/library/system.web.ihttpmodule(v=vs.110).aspx)で Server ヘッダを改変/削除するという方法もありそうだけど([自作のHttpModule](http://rocketeer.dip.jp/sanaki/free/free152.htm)もこのタイプだけど・・・)、ヌケがある。

OPTIONS メソッドのURLが「*(アスタリスクだとWebサーバ全体の設定という意味)」の HTTP リクエストだ。

> C:\\>StreamRelay.NET.exe -localport 0 -remotehost 192.0.2.3 -remoteport 80 -InputResponseCharset utf-8 -OutputResponseCharset shift_jis
> OPTIONS * HTTP/1.0​

> HTTP/1.1 400 Bad Request​
> Content-Type: text/html​
> **Server: Microsoft-IIS/8.5​**
> X-Powered-By: ASP.NET​
> Date: Mon, 12 Nov 2018 14:07:42 GMT​
> Connection: close​
> Content-Length: 33​
​
> 要求が正しくありません​

こんな感じ。

どうも [System.Web.HttpModule](https://msdn.microsoft.com/en-us/library/system.web.ihttpmodule(v=vs.110).aspx)、さらには [System.Web.HttpApplication](https://msdn.microsoft.com/en-us/library/system.web.httpapplication(v=vs.110).aspx) のどのイベントも呼ばれずに、レスポンスが返ってしまう。
どのイベントも呼ばれないので、マネージドな HttpModuleでは改変/削除できない(というか何もできない)。

**これが、ネイティブモジュール(ISAPIフィルタの事!?)の URLRewriteだと、消えてくれる。**

### IISの結論

**ネイティブモジュールの UrlRewiteを使え。マネージドなHttpModuleでServerヘッダが改変/削除できると思うな**

### 挙動からの推測

「400 Bad Request​」という事から、HTTP.SYS はOPTIONSメソッドでのURLが「*」は対応していて、一方でIIS側では、HttpApplicationクラスのインスタンスを作成中(コンストラクタ)に、URLの解釈(どの物理パスが対応するかとか)あたりでコケている(コンストラクタで例外)のではないか?
HTTP.SYS的には、(HttpApplicationクラスのコンストラクタで失敗している)IISに渡しているので、ServerヘッダはIISのものがついているのではないか。
そして、IISのServerヘッダなので、HTTP.SYSのServerヘッダの隠蔽処理は反応しないのではないか。

一方で、ネイティブモジュールは HttpApplicationクラスの生成前からのIISの処理に割り込みをかけれるのではないか。

## その他(ASP.NETなど)

↓を参照してくれ
* [【ASP.NET】HTTPレスポンスヘッダーからASP.NET/IISの情報を削除する](https://qiita.com/t_takahari/items/b48db4605adb7e5f818c)