ModSecurityによるStruts脆弱性対策

日本のStruts1の脆弱性(CVE-2014-0114)対応は素早く粛々と行われているようで、なによりです。

http://qiita.com/kawasima/items/670d2591bc8fea19dc1d

こちらの記事で

1. BeanUtilsのResolverを差し替える方法
2. RequestProcessorを差し替える方法

について書きました。

どちらもJavaアプリケーションレイヤでの対策ですが、[ModSecurity](http://www.modsecurity.org/)を使ってもキチンと穴塞げるようなのでやってみました。これはAPサーバの前にApacheがいることが前提になりますが、対策は非常に簡単です。

## ModSecurityのセットアップ

Ubuntu系は、aptでインストールできます。

```shell-session
% sudo apt-get install libapache2-modsecurity
```

そうすると、`/etc/modsecurity/modsecurity.conf-recommended`にコンフィグのexampleが置かれているはずなので、これをコピーして編集します。

```shell-session
% sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
```

ファイル最後尾にでも、

```
SecRule ARGS_NAMES "(^|\.)[cC]lass\." "deny,log,status:403"
```

を追加します。これはclass,Classを含むネストしたパラメータの場合、そのリクエストを拒否し、ログを書き、403でレスポンスを返すというルールです。詳しくはリファレンスマニュアルをみてください。
https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual

`/etc/apache2/mods-available\mod-security.conf`中に、`Include "/etc/modsecurity/*.conf"`の記述があるので、後はモジュールを有効化して、再起動するだけです。

```shell-session
% sudo a2enmod mod-security
% sudo apache2ctl restart
```

## テスト

それではこのルールが有効かどうか試してみます。あとでマルチパートのリクエストもテストするので、そういうときはJMeterを使うと便利です。

スレッドグループにHTTPリクエストのサンプラーを追加し、パスやパラメータを設定します。

![SnapCrab_NoName_2014-5-3_0-16-59_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/8475/88db6ab5-1fa4-3fdf-24bc-1587e84b8d43.png)

これを"結果をツリーで表示"のリスナーを追加して実行すると、実行結果が見れます。

![SnapCrab_NoName_2014-5-3_0-17-34_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/8475/1d7a23a2-1ea6-155e-0e3a-9d33ffad5dde.png)

ちゃんと、403で弾かれてますね！

さて、問題はServletFilterでは難しかったMultipartのパラメータもチェックできるか、です。mod_securityはMultipartも一度パースして、再構成して後ろのフックに回す機能があります。JMeterでマルチパートのリクエストを作るのはチョー簡単です。以下のようにメソッドをPOSTにしてMultipartのチェックボックスにチェックつけるだけです。

![SnapCrab_NoName_2014-5-3_0-22-48_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/8475/fc17d5b2-35c6-a7a8-c91e-7dd9c082cc03.png)

さて、こちらも実行してみます。

![SnapCrab_NoName_2014-5-3_0-25-54_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/8475/8d9c819a-af9d-ae96-2710-c0ef06fc05a2.png)

ヤリました！マルチパートでもちゃんと403が返りルールにしたがってチェックかかっていることが分かります。

正しくModSecurityが動いた結果かどうかは、auditログが出力されているので、そちらで確認できます。

```:/var/log/apache2/modsec_audit.log
[03/May/2014:00:25:06 +0900] U2O40n8AAQEAADImF4IAAAAB 127.0.0.1 32834 127.0.0.1 80
--de079d50-B--
POST / HTTP/1.1
Connection: keep-alive
Content-Length: 238
Content-Type: multipart/form-data; boundary=ioU4y3E5yzasxHc7HgXGrFwUCF9AKmWVKAHv5Zh
Host: localhost
User-Agent: Apache-HttpClient/4.2.6 (java 1.5)

--de079d50-I--
class%2eclassLoader%2ehoge=hehehe
--de079d50-F--
HTTP/1.1 403 Forbidden
Vary: Accept-Encoding
Content-Length: 277
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1

--de079d50-E--
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /
on this server.</p>
<hr>
<address>Apache/2.2.22 (Ubuntu) Server at localhost Port 80</address>
</body></html>

--de079d50-H--
Message: Access denied with code 403 (phase 2). Pattern match "(^|\\.)[cC]lass\\." at ARGS_NAMES:class.classLoader.hoge. [file "/etc/modsecurity/modsecurity.conf"] [line "207"]
Action: Intercepted (phase 2)
Stopwatch: 1399044306059830 1099 (- - -)
Stopwatch2: 1399044306059830 1099; combined=91, p1=34, p2=44, p3=0, p4=0, p5=13, sr=0, sw=0, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.6.3 (http://www.modsecurity.org/).
Server: Apache/2.2.22 (Ubuntu)

--de079d50-J--
Total,0

--de079d50-Z--

```

こんな感じでログが出力されています。大丈夫そうですね。

## ModSecurityによるオーバーヘッド

さて、既存の環境にModSecurityを適用する場合、気になるのはその性能オーバーヘッドです。
せっかくのJMeterなのでスループットを測ってみます。サーバサイドの処理はなく普通のApacheのエラーを返すだけの処理です。


添付ファイル(500kb)あり (100スレッド/無限ループ)

|ModSecurity| スループット(/sec) | 90%ライン (msec)|
|:-----------|------------:|------------:|
|有(正常リクエスト)|527|297|
|有(正常リクエスト)|504|335|
|無|1147|6|

添付ファイルなし (100スレッド/無限ループ)

|ModSecurity| スループット(/sec) | 90%ライン (msec)|
|:-----------|------------:|------------:|
|有(正常リクエスト)|6415| 8|
|有(攻撃リクエスト)|4444| 37|
|無|7199|  1|

マルチパートをパースして再構成するので、やはりマルチパートでのリクエストが多い場合は、結構なオーバーヘッドになるようです。が、Apacheに余裕があってファイルアップロードのリクエストがそんなに殺到するものでない場合においては、90%ラインは実用的な数値なので、ModSecurityの導入検討の価値はあるかと思います。