Apacheセキュリティ設定

## 概要
**Apache の設定**について共通化できるセキュリティ設定とその各項目についてまとめた。

## 設定例
### 必須設定
```apache
cat << _EOF_ > /etc/httpd/conf.d/security.conf
# バージョン情報の隠蔽
ServerTokens ProductOnly
Header always unset "X-Powered-By"
# httpoxy 対策
RequestHeader unset Proxy
# クリックジャッキング対策
Header always set X-Frame-Options "SAMEORIGIN"
# XSS対策
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Content-Type-Options "nosniff"
# XST対策
TraceEnable Off

<Directory /var/www/html>
    # .htaccess の有効化
    AllowOverride All
    # ファイル一覧出力の禁止
    Options -Indexes
</Directory>
_EOF_
```
```bash
cat /dev/null > /etc/httpd/conf.d/autoindex.conf ;
cat /dev/null > /etc/httpd/conf.d/userdir.conf ;
cat /dev/null > /etc/httpd/conf.d/welcome.conf ;
```

#### 注意事項
* 外部サイトからiframeで呼び出しできなくなる

### 任意設定
```apache
cat << _EOF_ > /etc/httpd/conf.d/security-strict.conf
# DoS 攻撃対策
LimitRequestBody 10485760
LimitRequestFields 50
# slowloris 対策
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500

# HTTPメソッドの制限
<Directory /var/www/html>
    Require method GET POST
</Directory>

<Directory "/var/www/cgi-bin">
    Require all denied
</Directory>
_EOF_
```

#### 注意事項
* GET/POST 以外使えなくなる
* cgi-bin が使えなくなる

## 想定環境
本記事は主に CentOS で **Yum** を使って Apache をインストールしている想定での情報のため、環境に合わせて適宜読み替えること。
対象とする **Apache** のバージョンは、現在サポートされている **2.4** のみ[^support]。詳細は [Apache HTTP Server のサポート期限](http://qiita.com/bezeklik/items/7e2c02c3eabd2a416231) を参照。

[^support]: <q cite="https://qiita.com/bezeklik/items/7e2c02c3eabd2a416231">Apache 2.2 は2017年7月11日に 2.2.34 をリリースし、2017年12月31日をもって2.2系の開発終了を宣言している。</q><cite>[Apache HTTP Server のサポート期限 #Apache - Qiita](https://qiita.com/bezeklik/items/7e2c02c3eabd2a416231) - <i>qiita.com</i></cite>

### デフォルト値検証の環境情報

* CentOS 7.2.1511 (CentOS-7-x86_64-Minimal-1511.iso)
* Apache 2.4.6 (`yum install httpd`)
* PHP 5.4.16 (`yum install php`)

## ポリシー

* Yum によるパッケージ管理
    * ソースからコンパイル？そんなものウチにはないよ。
* デフォルトの設定ファイルに極力手を入れない
* コストパフォーマンス優先
    * 成立の可能性が低い脆弱性への対応で汎用性やシンプルさが失われるような設定は避ける

# 設定項目
## 情報の隠匿（隠蔽）
バージョンなどの情報隠匿については、セキュリティ対策としての実効性に関する議論 [^srad] が一応ある。

[^srad]: <q>ApacheやOSのバージョンを表示しないようにする方法や、PHPでX-Powered-Byを応答しなくする方法が紹介された記事ですが、コメント欄や260件以上の登録を集めたはてなブックマークでは賛否両論になっています。</q><cite>[サーバのバージョンは隠すのが常識? | スラド オープンソース](http://opensource.srad.jp/story/07/09/03/0219247/) - <i>opensource.srad.jp</i></cite>

### バージョン情報（ServerTokens）
```text:HTTPレスポンスヘッダー
Server: Apache/2.4.6 (CentOS) PHP/5.4.16
```
Apache 2.2[^servertoken22] / 2.4[^servertoken24] 共に `ServerTokens` ディレクティブのデフォルト値は `Full` のため、 HTTP ヘッダーに上記のように Apache のバージョンが出力される。

```apache
ServerTokens ProductOnly
```

上記のように `ServerTokens` ディレクティブに `Prod` または `ProductOnly` を指定することで、以下のように Apache のバージョン情報を隠蔽できる。

```text:HTTPレスポンスヘッダー
Server: Apache
```
[^servertoken22]: <q cite="https://httpd.apache.org/docs/2.2/ja/mod/core.html#servertokens">このディレクティブは、クライアントに送り返す Server 応答ヘッダ内に、サーバの一般的な OS 種別や、 コンパイルされて組み込まれているモジュールの情報を含めるかどうかを指定します。</q><cite>[core - Apache HTTP サーバ バージョン 2.2](https://httpd.apache.org/docs/2.2/ja/mod/core.html#servertokens) - <i>httpd.apache.org</i></cite>
[^servertoken24]: <q cite="https://httpd.apache.org/docs/2.4/ja/mod/core.html#servertokens">このディレクティブは、クライアントに送り返す Server 応答ヘッダ内に、サーバの一般的な OS 種別や、 コンパイルされて組み込まれているモジュールの情報を含めるかどうかを指定します。</q><cite>[core - Apache HTTP サーバ バージョン 2.4](https://httpd.apache.org/docs/2.4/ja/mod/core.html#servertokens) - <i>httpd.apache.org</i></cite>

### ServerSignature
```text
Apache/2.2.15 (CentOS) Server at 192.168.56.101 Port 80
```
`ServerSignature` ディレクティブは、 サーバーが生成するドキュメント（エラーメッセージ、mod_proxy における FTP のディレクトリーリスト、 mod_info の出力等）の最下行に上記のような出力を付与する設定を行う。

```apache
ServerSignature Off
```

Apache 2.2[^serversignature22] / 2.4[^serversignature24] 共にデフォルト値は `Off` になっているが、CentOS 6.x の Apache 2.2 ではディストリビューション側の設定で `On` になっているためか、書き換える必要がある。

なお、 httpd.conf の設定を変更していない場合、 `<Directory "/var/www/html">` 内で指定しないと機能しない。

[^serversignature22]: https://httpd.apache.org/docs/2.2/ja/mod/core.html#serversignature
[^serversignature24]: https://httpd.apache.org/docs/2.4/ja/mod/core.html#serversignature

### TRACEメソッドの無効化（XST対策）
```apache
TraceEnable Off
```
XSS と TRACE メソッドを組み合わせた **XST (クロスサイトトレーシング)攻撃**への対策。
BASIC認証のIDとパスワード等が漏洩する危険があるが、サポート切れの古いOSなど攻撃成立条件は限定的[^XST] [^XST2] である。
なお、TRACE メソッドは `<Limit>` や `<LimitExcept>` ディレクティブでは制限できない。[^TRACE]

[^XST]: http://blog.tokumaru.org/2013/01/TRACE-method-is-not-so-dangerous-in-fact.html
[^XST2]: http://n.pentest.ninja/?p=952
[^TRACE]: https://httpd.apache.org/docs/2.4/ja/mod/core.html#limit

### エンティティタグ（ETag）
過去の Apache では HTTP ヘッダーに出力する ETag に inode 番号を強制的に利用していた[^ETag]ため、ETag ヘッダーからファイルの inode 番号を入手されるリスクがあった。[^vuln_11438]
[^vuln_11438]: http://www.iss.net/security_center/reference/jp/vuln/apache-mime-information-disclosure.htm
ただ、検証および調査したところ Apache 2.4.0 からはデフォルト値は `MTime Size` になっており、2.4 系ではセキュリティ面では本設定は気にする必要はない。
2.2 系では `FileETag MTime Size` または `FileETag None` を指定するといいだろう。

ETagを削除して `Last-Modified` ヘッダーを使えば HTTP ヘッダーのサイズがその分少なくなるというメリットがある。ETag を出力しない設定は以下の通り。

```apache
FileETag None
```
上記設定ではうまく ETag が消えない場合は、以下のように消すことも可能。

```apache
Header unset ETag
```

#### FileETag 設定の挙動検証
| FileETag | ETag |
|----------|------|
| (未指定)  | "220-529841bdd9a78" |
| MTime Size | "220-529841bdd9a78" |
| All      | "905069-220-529841bdd9a78" |
| INode    | "905069" |
| MTime    | "529830adcea90" |
| Size     | "220" |

公式リファレンスのデフォルト値は未だに `FileETag INode MTime Size` と記載されている[^ETag]が、検証環境で検証したところデフォルトでは `MTime Size` だった。~~リファレンスの更新漏れか、あるいはディストリビューションのパッケージでデフォルト値を変更しているか。~~はてブで指摘があったのでソースを調べたら[^ETag-github]Apache本体のデフォルト値が 2.4.0 から変わってたので、やはりリファレンスの更新漏れの模様。（英語版[^ETag-ref24-en]は正しく修正されている by @matuuさん）

[^ETag-ref24-en]: http://httpd.apache.org/docs/2.4/en/mod/core.html#fileetag

```diff:docs/manual/mod/core.xml
-<default>FileETag INode MTime Size</default>
+<default>FileETag MTime Size</default>
 <contextlist><context>server config</context><context>virtual host</context>
 <context>directory</context><context>.htaccess</context>
 </contextlist>
 <override>FileInfo</override>
+<compatibility>The default used to be "INode&nbsp;MTime&nbsp;Size" in 2.3.14 and
+earlier.</compatibility>
```
```diff:include/http_core.h
-#define ETAG_BACKWARD (ETAG_MTIME | ETAG_INODE | ETAG_SIZE)
 #define ETAG_ALL   (ETAG_MTIME | ETAG_INODE | ETAG_SIZE)
+/* This is the default value used */
+#define ETAG_BACKWARD (ETAG_MTIME | ETAG_SIZE)
```
```diff:modules/dav/fs/repos.c
     if (ctx->finfo.filetype != APR_NOFILE) {
          return apr_psprintf(ctx->pool, "\"%" APR_UINT64_T_HEX_FMT "-%"
-                            APR_UINT64_T_HEX_FMT "-%" APR_UINT64_T_HEX_FMT "\"",
+                            APR_UINT64_T_HEX_FMT "\"",
-                            (apr_uint64_t) ctx->finfo.inode,
                             (apr_uint64_t) ctx->finfo.size,
                             (apr_uint64_t) ctx->finfo.mtime);
      }
```

[^ETag]: http://httpd.apache.org/docs/2.4/ja/mod/core.html#fileetag
[^ETag-github]: https://github.com/apache/httpd/commit/ba86234a7e627a50fdedc50b49ceaf40465911cb

### X-Powered-By
```
X-Powered-By: PHP/5.4.16
```
HTTP ヘッダーに上記のように PHP などのバージョンが出力されている場合があるので、以下のように Apache 側でヘッダーを強制削除する。

```apache
Header always unset "X-Powered-By"
```

PHP の場合は以下のように php.ini の `expose_php` ディレクティブ [^expose_php] で非表示にする設定が可能だが、Apache 側で一元的に強制削除した方が設定漏れのリスクがないだろう。

```ini:php.ini
expose_php = Off
```

[^expose_php]: http://php.net/manual/ja/ini.core.php#ini.expose-php


### Options -Indexes
```apache
<Directory /var/www/html>
    Options -Indexes
</Directory>
```
Apache 2.0/2.2/2.4 共に `Options` のデフォルト値は `All`。
`DirectoryIndex` ディレクティブ [^DirectoryIndex] で指定したファイル (index.html等) がディレクトリー内に無い場合に mod_autoindex がディレクトリー内のファイル一覧を整形して返す。
[^DirectoryIndex]: https://httpd.apache.org/docs/2.4/ja/mod/mod_dir.html#directoryindex

### autoindex.conf
```bash
cp /dev/null /etc/httpd/conf.d/autoindex.conf
```

または

```bash
> /etc/httpd/conf.d/autoindex.conf
```
iconsの設定等が記載されているが、ディレクトリ一覧は表示させないため利用しない。ファイル自体を削除するとアップデート時に再作成されるので、空ファイルにする。

### welcome.conf
```bash
cp /dev/null /etc/httpd/conf.d/welcome.conf
```

または

```bash
> /etc/httpd/conf.d/welcome.conf
```

ドキュメントルートに index.html がない場合など Forbidden になると OS のウェルカムページが表示されるが、余計な情報になるので削除。autoindex.conf と同様に削除するとアップデート時に再作成されるため空ファイルにする。

## セキュリティ設定

### AllowOverride
```apache
<Directory /var/www/html>
    AllowOverride All
</Directory>
```
`/etc/httpd/conf.d/userdir.conf` の `<Directory "/home/*/public_html">` で指定されている `AllowOverride` 以外はすべて `None` が指定されているので、.htaccess を利用するためにドキュメントルート配下を個別に許可する。

### HTTP メソッドの制限
```apache
<Directory /var/www/html>
    Require method GET POST
</Directory>
```

### X-Frame-Options（クリックジャッキング対策）
```apache
Header always append X-Frame-Options SAMEORIGIN
```

**X-Frame-Options** HTTP レスポンスヘッダーは、ブラウザーがページを `<frame>` または `<iframe>` の内部に表示することを許可するかを示すことができる。
クリックジャッキング対策として IE8 から実装されたオプションヘッダー。
自分のサイトのコンテンツが他のサイトに埋め込まれないことを保証する。[^xfo-mdn]

[^xfo-mdn]: https://developer.mozilla.org/ja/docs/HTTP/X-Frame-Options
| 設定値 | 内容 |
|---|---|
| `DENY` | サイト側の意図に関わらず、ページをフレーム内に表示することはできない。同じサイトのページをフレーム内に読み込むことも不可能になる。 |
| `SAMEORIGIN` | 自身と生成元が同じフレーム内に限りページを表示することができる。外部サイトのフレーム内にページを読み込むことを不可能にする。 |
| `ALLOW-FROM uri` | 指定された生成元に限り、ページをフレーム内に表示できる。Chrome、Safariは未対応。[^xfo-chromium] |

[^xfo-chromium]: [Issue 511521 - chromium - \`X-Frame-Options\` does not support the \`allow-from\` directive. - Monorail](https://code.google.com/p/chromium/issues/detail?id=511521)

`X-Frame-Options` に対応するブラウザーのバージョンは IE8 以上、Firefox 3.6.9 以上、Chrome 4.1.249.1042 以上、Safari 4 以上、Opera 10.50 以上。[^xfo]

[^xfo]: [X-Frame-Options、ブラウザ対応完了 | マイナビニュース](http://news.mynavi.jp/articles/2010/09/10/x-frame-options-for-all-browsers/)

Google、Twitter、Yahoo! JAPAN などで `SAMEORIGIN` が指定されている。
Facebook では `DENY` が指定されている。

### X-XSS-Protection（XSSフィルター機能）

```apache
Header always set X-XSS-Protection "1; mode=block"
```
`X-XSS-Protection` はブラウザの XSS フィルター機能を制御できるレスポンスヘッダー。
`0` は無効、 `1` は有効（部分的書き換え）、 `1; mode=block` は有効（表示の完全な停止）を意味する。
サイトの XSS 対策に問題はなく誤検知をなくしたい場合は `0` を、そうでない場合は `1; mode=block` を指定するのが望ましく、デフォルトの `1` の状態は望ましくない。 [^xss-protection]

Google、Twitter、Yahoo! JAPAN などで指定されている。
Facebook では `0` が指定されている。

[^xss-protection]: http://www.slideshare.net/masatokinugawa/xxn-ja/98

### X-Content-Type-Options

```apache
Header always set X-Content-Type-Options nosniff
```
`X-Content-Type-Options` レスポンスヘッダーの値に `nosniff` を設定して送信すると、Internet Explorer が MIME Sniffing 機能で content-type 宣言を回避するのを防止できる。[^nosniff]

[^nosniff]: [2008/9/3 - Internet Explorer 8 のセキュリティ Part VI: Beta 2 の更新項目](https://msdn.microsoft.com/ja-jp/dd218497.aspx)

Facebook、Twitter、Yahoo! JAPAN などで指定されている。

### Content Security Policy (CSP)
素人にはお勧めできない。
https://content-security-policy.com/
http://blog.hash-c.co.jp/2013/12/Content-Security-Policy-CSP.html

### httpoxy 対策
Foo: Bar っていう header 送ったら CGI の spec 的には HTTP_Foo = Bar にしてくれるっていう仕様を突いて PROXY: xxx っていうheader送ると HTTP_PROXY書き換えられるんじゃねっていう脆弱性。[^294900783]
[HTTPOXY Vulnerability Checking Tool](https://httpoxy.rehmann.co/) でテストできる。
以下のソフトウエアが影響を受ける。[^JPCERT-AT-2016-0031]

 - PHP (CVE-2016-5385)
 - GO (CVE-2016-5386)
 - Apache HTTP Server (CVE-2016-5387)
 - Apache Tomcat (CVE-2016-5388)
 - HHVM (CVE-2016-1000109)
 - Python (CVE-2016-1000110

[^294900783]: http://b.hatena.ne.jp/entry/294900783/comment/yosuke_furukawa
[^JPCERT-AT-2016-0031]: [CGI 等を利用する Web サーバの脆弱性 (CVE-2016-5385 等) に関する注意喚起](https://www.jpcert.or.jp/at/2016/at160031.html)

### LimitRequestBody
このディレクティブはリクエストボディに許されるバイト数を指定する。
ディレクティブが書かれたコンテキスト（サーバ全体、ディレクトリ、ファイル、ロケーション）内で許容する HTTP リクエストメッセージボディのサイズに制限をかけることができる。
デフォルト値は `0` で無制限。上限は `2147483647` (2GB) まで。

```apache
LimitRequestBody 10485760
```
10MiB に制限したい場合は上記のように記述。リファレンスで DoS 攻撃を避けるのに有効としている。

なお、PHP では以下のデフォルト値が設定されているので併せて確認したい。

```ini:php.ini
memory_limit = 128M
post_max_size = 8M
upload_max_filesize = 5M
```

### LimitRequestFields
このディレクティブは HTTP リクエストにおいて許可するリクエストヘッダフィールド数を指定する。
デフォルト値は `100` になっている。

```apache
LimitRequestFields 50
```
リファレンスには「リクエストヘッダーフィールドの数が 20 を超えることはほとんどない。」[^limitrequestbody] とある。また、DoS 攻撃を避けるのに有効としている。

なお、値を 20 に設定していたら特定の Web ページで Chrome においてのみ Bad Request が返されたとする報告があり、参照する Web ページやブラウザによって挙動が異なることもあるようだ。 [^bad_request]

[^limitrequestbody]: http://httpd.apache.org/docs/2.4/mod/core.html#LimitRequestFields

[^bad_request]: [ChromeのみBad Requestで特定ページが開けない問題 - Qiita](https://qiita.com/yuta-matsumoto/items/46f10e432fd3ba447cb3)

### RequestReadTimeout
```apache
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
```
slowloris [^slowloris] 対策で実装された mod_reqtimeout モジュールで使用できるディレクティブ。
2.2.15 以降に実装され、2.3.15 以降はデフォルトで有効になった。

AWS の ELB を利用している場合、 ELB の `Connection Settings: Idle Timeout` の値が Apache の `RequestReadTimeout header` の最低値よりも大きいと、 Apache のエラーログに 408 が大量に吐かれてしまうようなので注意。[^slowloris-elb]

[^slowloris]: [Apacheに新たな脆弱性発見 | スラド セキュリティ](http://security.srad.jp/story/09/06/23/0455215/)

[^slowloris-elb]: [「ELBからの通信で408が多発する」件で、結局どうすべきか調べたのでまとめた - 双六工場日誌](http://sechiro.hatenablog.com/entry/2014/12/07/%E3%80%8CELB%E3%81%8B%E3%82%89%E3%81%AE%E9%80%9A%E4%BF%A1%E3%81%A7408%E3%81%8C%E5%A4%9A%E7%99%BA%E3%81%99%E3%82%8B%E3%80%8D%E4%BB%B6%E3%81%A7%E3%80%81%E7%B5%90%E5%B1%80%E3%81%A9%E3%81%86%E3%81%99)

## セキュリティテスト
CentOS 7.2.1511 に yum で Apache をインストールして設定変更していないケースをテストした結果。

```bash
[root@localhost program]# perl ./nikto.pl -h 127.0.0.1
- ***** SSL support not available (see docs for SSL install) *****
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          127.0.0.1
+ Target Hostname:    127.0.0.1
+ Target Port:        80
+ Start Time:         2016-01-16 10:00:00 (GMT9)
---------------------------------------------------------------------------
+ Server: Apache/2.4.6 (CentOS) PHP/5.4.16
+ Server leaks inodes via ETags, header found with file /, fields: 0x220 0x529841bdd9a78
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ PHP/5.4.16 appears to be outdated (current is at least 5.6.9). PHP 5.5.25 and 5.4.41 are also current.
+ Apache/2.4.6 appears to be outdated (current is at least Apache/2.4.16). Apache 2.2.31 is also current for the 2.x branch.
+ Allowed HTTP Methods: GET, HEAD, POST, OPTIONS, TRACE
+ OSVDB-877: HTTP TRACE method is active, suggesting the host is vulnerable to XST
+ Retrieved x-powered-by header: PHP/5.4.16
+ OSVDB-3092: /test.php: This might be interesting...
+ 8225 requests: 0 error(s) and 10 item(s) reported on remote host
+ End Time:           2016-01-16 10:00:11 (GMT9) (11 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
```
# Apache 関連記事
* [Apacheセキュリティ設定](http://qiita.com/bezeklik/items/1c4145652661cf5b2271)
* [Apache HTTP Server のサポート期限](http://qiita.com/bezeklik/items/7e2c02c3eabd2a416231)
* [Apache のログをコマンドラインで集計する](http://qiita.com/bezeklik/items/f5c292c4360cde140bef)
* [Apache の情報をコマンドラインで取得する](http://qiita.com/bezeklik/items/7bbfcbcfeb05c1d57fec)
* [IPアドレスから国や都市を判別する (GeoIP)](http://qiita.com/bezeklik/items/927e1c52c8c0aefb1f06)
* [Apache チューニング スクリプト](http://qiita.com/bezeklik/items/85f4001a2517be5fe4c0)