Selenium と OWASP ZAP を使った自動脆弱性検査への道標
※当サイトにはプロモーションが含まれています。
公開日:
更新日:
Webアプリケーションをローカル環境で開発している場合に、Selenium と OWASP ZAP を使って自動的に脆弱性検査を実行するための設定・実行手順について説明します。使用するプログラミング言語には依存しない範囲で書くので、具体的な記述方法までは踏み込みません。
前置き
- 大まかに言うと、開発中のWebアプリケーションに対してまず Selenium を使ったテストを実行し(この時、ブラウザのプロキシ設定をZAPにしておきます)、その後で OWASP ZAP による脆弱性検査を行います。
- 自動といっても、今回はローカルのPC上でブラウザやZAPがGUI起動することを前提としています。
- 今回のテストを、開発中プログラムのファイル更新時に実行させることもできますが、自動脆弱性検査は時間が掛かりますので、まとまった時間が取れるタイミングで実行するのがよいのではないかと思います。
- CI(継続的インテグレーション) に組み込む場合も、夜間に一度実行する程度でよいと思います。
前提知識
OWASP ZAP について
- オープンソースのWebアプリケーション脆弱性検査ツールです。
- 無料で自動的な脆弱性検査を実行することができます。
- 詳しくは、こちらを参照して下さい。
Selenium Server について
- ブラウザを操作するソフトウェアです。デーモンとして常駐し、REST API のインターフェース(Json Wire Protocol)を通してクライアントからの命令を受信することでブラウザを操作します。クライアント側では、いろいろなプログラミング言語でブラウザの操作処理やチェック処理を記述することができ、Webアプリケーションが意図した通りに動いているかテストすることができます。
- 公式サイト
- Selenium Server の RESTful Web インターフェースの仕様
Seleniumを使う理由
- ZAP でスパイダー検索やアクティブスキャンを行う前に、Selenium のテスト(ブラウザを使ったテスト)をZAP経由(ブラウザにプロキシ設定する)で実行させることにより、テストしたURL(やパラメータ)がZAPに記録されます。その後のZAPによるアクティブスキャンでは、確実にこのURLを対象にすることができます。また、ZAPを通してWebアプリケーションにアクセスしている時点で、リアルタイムにパッシブスキャン(非破壊的な脆弱性検査)が実行されます。
- OWASP ZAP に限りませんが、この種のツールで自動でテストする場合、事前に手動(ブラウザを使って)でWebサイトにアクセスする手順が指示されていることがあります。Seleniumによるテストは、その代わりの操作になります。
- ということなので、ZAPに確実に検査させたい部分はSeleniumのテストを書いておきましょう(必要なパラメータ付きでリクエストを送る処理を書くということです)。
全体の流れ
1つのコマンドを実行すると、以下の操作が順番に実行されるようにします。タスクランナーツールやCIツールを使って、それぞれの手順を順番に実行させてもよいでしょうし、スクリプト言語で全て書いてしまってもよいと思います。但し、特にZAPを操作するような部分は、ZAPのクライアントライブラリを使ってプログラムを書く必要があります。
- Webサーバー・DBサーバ等、Webアプリケーションが動作するために必要なソフトウェアを起動する
- ユニットテスト(Seleniumを使わないテストのみ)を実行する(オプション)
- Selenium Server を起動する
- Seleniumを使ったテストを実行する(オプション)
- ZAP を起動する
- ブラウザにプロキシ設定(ZAPを利用)を行って、Seleniumのテストを実行する
- ZAPのContext等を設定する
- ZAPのスパイダー検索を実行する
- ZAPのアクティブスキャンを実行する
- ZAPのセッションを保存する
- ZAPを終了する
- Selenium Server, Webサーバー・DBサーバー等を終了する
手順
1. Webサーバー・DBサーバ等、Webアプリケーションが動作するために必要なソフトウェアを起動する
- Webアプリケーションの稼働に必要なソフトウェアを起動します。
- Monit 等のサービス管理ツールを使って、まとめて起動させるのもよいでしょう。
2. ユニットテスト(Seleniumを使わないテストのみ)を実行する(オプション)
- 各プログラミング言語用に用意されたユニットテスト・フレームワークを使った通常のユニットテスト(Seleniumは使わないテストのみ)を実行します。
- 必ずしも脆弱性検査と一緒にまとめて実行する必要はないので、オプションとしました。
3. Selenium Server を起動する
- 予めダウンロードしておいた Selenium Server (実体は jar ファイル)を javaコマンドで実行するだけです。
補足: Selenium Server のダウンロード
- 以下のページから Selenium をダウンロードして、適当なディレクトリに配置します。
- Downloadsページ の Selenium Server をダウンロードします。(jarファイルです)
4. Seleniumを使ったテストを実行する(オプション)
- ユニットテスト・フレームワークを利用して、Selenium用に記述したテストを実行します。
- 詳細は 手順6に書きます。
- 後の手順で、ブラウザにZAPをプロキシとして設定して同じテストを行えるので、この手順はオプションとしました。
5. ZAP を起動する
- コマンドラインで ZAPを起動するためには、zap.sh (Linux/Macの場合) / zap.bat (Windowsの場合)ファイルを実行します。
- 起動には少し時間が掛かるため、完全に起動するまで待つ処理を組み込む必要があるでしょう。
補足:ZAPをダウンロードしてインストールする
- 以下のページで、ZAPをダウンロードすることができます。
6. ブラウザにプロキシ設定(ZAPを利用)を行って、Seleniumのテストを実行する
- 手順4と同じ内容の Selenium 用テストを実行するのですが、その際ブラウザがZAPをプロキシとして使用するようにします。
補足:6-1 Selenium のクライアントライブラリをダウンロード
- Downloads に各言語用クライアントライブラリへのリンクが載っていますので、利用する言語のライブラリをダウンロードして使用します。
- PHPは公式なライブラリがありませんが、サードパーティからいろいろな実装が公開されています。
- phpunit/phpunit-selenium - Packagist 等が人気のようです。私はこれを使っています。
補足:6-2 Seleniumを使ったテストを書く
- ユニットテスト・フレームワークを利用して、Seleniumを使ったテストを書きます。
- 使用しているSeleniumのクライアントライブラリを利用して、ブラウザの操作や意図した通りの動作になっているかチェックする処理を記述します。
- Seleniumを使ったテストのファイルは、通常のユニットテストのファイルと区別できるように、ファイル名に規則を作りそれに従うようにします。(例えば、「xxxxSelenium.java」のように末尾が Seleniumになるなど)。
- 以下のツールを使うと、ブラウザ上の操作を記録させることでテストコードを生成することができます。いろいろなライブラリに対応しています。
補足:6-3 Seleniumのテスト時に、ブラウザがプロキシとしてZAPを使うようにする
- 6-2で書いたSeleniumのテスト実行開始時に、ブラウザがZAPをプロキシとして使用するように設定する処理を記述します。Seleniumのテストクラスをなるべくそのまま利用し、テストが実行される最初の段階でブラウザのプロキシ設定処理が挟み込まれるような形にするのがよいです。
- 例えば、Selenium用に書いたテストクラスを継承させた別のテストクラスを作成し、テストの最初に実行される
setUp()メソッドをオーバーライドします。このメソッド内で、ブラウザがZAPをプロキシとして使う設定を記述します。(あくまで一つの方法です) - このテストクラスファイル名もまた区別できるように、命名規則を作って従うようにします。(例えば、「 xxxxcZap.java」のように末尾が Zap になるなど)
- 通常、ユニットテスト・フレームワークにはテストファイル名のフォーマットを指定して該当するファイルのみ実行する機能があるので、このような方針により Selenium だけを使ったテストや、ZAP も合わせて使ったテストのみを実行することができるようになります。
7. ZAPのContext等を設定する
- ZAP も Selenium と同じくWebのインターフェースを持っており、特定のURLにリクエストを送ることで操作することができるようになっています。
- ApiDetails - zaproxy に、このAPIを操作するための各プログラミング言語用ライブラリが載っています。
- ※ PHP用ライブラリの開発は今のところ私が担当しています。
- ZAP の起動後、これらのライブラリを使ってテストしたいWebアプリケーションに合わせた設定を行います。例えば、以下のような設定を行うことが考えられます。
- Contextの設定
- 対象となるURLの正規表現を登録
- 認証方法の設定(自動でログインできるようになります)
- ログインURL
- ログインに使用するユーザー名・パスワード
- ログイン・インジケータの登録
- CSRF対策トークン用パラメータ名の登録
- Forced User Mode を有効にする
- ※ セッションクッキー名は事前に手動で登録しておく必要があります。今のところ、APIはないようです。
- Contextの設定
- テストする項目をプログラムで選択することはできますが、予めZAPのGUI上で設定(スキャンポリシー)しておけば、それがそのまま使用されます。
8. ZAPのスパイダー検索を実行する
- ZAPを操作するライブラリを使って、スパイダー検索を実行します。
- この時発見されたURLへのHTTPリクエスト・レスポンスに対して、パッシブスキャンが実行さます。検知された脆弱性はアラートタブに表示されます。
- 定期的にステータスを監視し、処理が終了するまで待つ処理を書く必要があります。
- APIでスパイダー検索をした場合、ZAPの [スパイダー]タブ上にデータは表示されません。
9. ZAPのアクティブスキャンを実行する
- ZAPを操作するライブラリを使って、アクティブスキャンを実行します。
- 検知された脆弱性は、アラートタブに表示されます。
- 定期的にステータスを監視し、処理が終了するまで待つ処理を書く必要があります。
- APIでアクティブスキャンを実行した場合、ZAPの [アクティブスキャン]タブ上にデータは表示されません。
10. ZAPのセッションを保存する
- ZAPのクライアントライブラリを使って、セッションを保存します(この時の状態が保存されます) 。その後、時間がある時に (人間が)ZAPを起動してそのセッションを読み込み、検知された脆弱性が本物かどうか調査する必要があります。
11. ZAPを終了する
- ZAPのクライアントライブラリを使って、ZAPを終了します。
12. Selenium Server, Webサーバー・DBサーバー等を終了する
- 必要に応じてこれらも終了させましょう。
その他
- 誤検知も多いと思いますので、このあたりの対応はノウハウを蓄積していく必要があります。テスト項目を絞ったり、テスト項目毎に Threshold や Strength を変更したり、テスト対象外とするURLを登録する機能など、いろいろな設定を試すことが必要になってくると思います。
- 自動で再ログインできる設定にしていない場合は、ログアウトURLは除外しておくとよいです。
- Webアプリケーションフレームワークの機能として用意されていることもあるようですが、このテスト中は認証機能を外すというやり方も考えられます。(今回はセキュリティに関するテストなので、あまりいいことではありませんが)
- ZAPによる脆弱性検査の項目のうち、特にベータ版やアルファ版の項目をテストに使用すると、いつまでたっても処理が終わらないものがあったります。原因はケースバイケースなので一言では言えないのですが、このような項目は事前にスキャンポリシーから外しておくとよいです。
- 現在、ZAP の API を利用するためのライブラリには共通の問題があり、一部正常に機能しないAPIがあります。ZAPのコミュニティには報告済です。
- ZAPに関連するツールは以下のWebページにいろいろ載っています。
- RelatedProjects - zaproxy
- 私は使ったことがありませんが、GruntからZAPを呼び出せるような npmパッケージや、Jenkins のプラグインがあるようです。
まとめ
- ちょっと面倒かもしれませんが、一部の手順だけ自動化するのでもよいと思います。
- 一度設定できてしまえばそれなりに楽です。
- 更に詳細が知りたい方がいましたら、ご連絡頂ければお答えします。
参考
- Security Testing in Development and QA - YouTube
- 自動検査をデモしている動画です。
- Ant でタスクを実行しています。
- Automated Security Testing - YouTube
- Selenium と ZAP を使った自動検査のプレゼンテーションです。
- こちらも Ant でタスクを実行しているようです。
- Remote Driver and JSON wire Protocol - YouTube
- Selenium Sever の API が、ただのWebのAPIであることがよく分かる動画です。
[最終更新日:2014年11月2日]
※ [2014-10-18] タイトルを少し変更しました。
