概要
Azure DevOps の Pipelines を使って、アプリケーションのセキュリティテストを実施する方法を記載します。 なお、今回は OWASP ZAP というオープンソースのツールを利用します。
OWASP ZAP とは
Open Web Application Security Project によって公開されている Zed Attack Proxy という名前のペネトレーションテストツールです。
OWASP ZAP は、対象の Web アプリケーションに対してリクエストを送信し、返ってきたレスポンスの内容から脆弱性の有無を判定します。
OWASP ZAP で実行できるスキャンには、以下の種類があります。
自動スキャン: 入力されたURLから自動的なクロールを開始し、見つかったページに対して「攻撃(スキャン)」を行う
静的スキャン: ユーザーが(モンキーテストのようにランダムに)操作した際のレスポンスをもとに脆弱性の有無を判定する
動的スキャン: 静的スキャンの際に操作した内容を、自動的にリクエスト内容を変えて再実行する
ZAP Docker
今回は Azure Pipelines で実行したいため、client版ではなく Docker版の ZAP Docker を利用します。
Image について
安定版:
docker pull owasp/zap2docker-stable
最新のweekly(週次)リリース:
docker pull owasp/zap2docker-weekly
最新のリリース:
docker pull owasp/zap2docker-live
ベアリリース: 非常に小さなDockerイメージ、ZAPの実行に必要な依存関係のみが含まれ、CI環境に最適の Image です。
docker pull owasp/zap2docker-bare
スキャンの種類について
Baseline Scan: ターゲットに対して 静的スキャンを実施します。(デフォルト: 1分間)
Full Scan: ターゲットに対して 静的スキャンを実施します。(デフォルト: 時間無制限)
API Scan: OpenAPI または GraphQL (post 2.9.0) によって定義された API に対して、動的スキャンを実施します。
オプションについて
オプションが多く非常に柔軟に設定ができます。
細かい設定の方法については機会があれば書きますが、今回は割愛します。
$ docker run --rm -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable zap-full-scan.py -h Usage: zap-full-scan.py -t <target> [options] -t target target URL including the protocol, e.g. https://www.example.com Options: -h print this help message -c config_file config file to use to INFO, IGNORE or FAIL warnings -u config_url URL of config file to use to INFO, IGNORE or FAIL warnings -g gen_file generate default config file(all rules set to WARN) -m mins the number of minutes to spider for (defaults to no limit) -r report_html file to write the full ZAP HTML report -w report_md file to write the full ZAP Wiki(Markdown) report -x report_xml file to write the full ZAP XML report -J report_json file to write the full ZAP JSON document -a include the alpha active and passive scan rules as well -d show debug messages -P specify listen port -D delay in seconds to wait for passive scanning -i default rules not in the config file to INFO -I do not return failure on warning -j use the Ajax spider in addition to the traditional one -l level minimum level to show: PASS, IGNORE, INFO, WARN or FAIL, use with -s to hide example URLs -n context_file context file which will be loaded prior to scanning the target -p progress_file progress file which specifies issues that are being addressed -s short output format - dont show PASSes or example URLs -T max time in minutes to wait for ZAP to start and the passive scan to run -U user username to use for authenticated scans - must be defined in the given context file -z zap_options ZAP command line options e.g. -z "-config aaa=bbb -config ccc=ddd" --hook path to python file that define your custom hooks
Azure Pipelines で実行する
azure-pipelines.yml の書き方を紹介します。
※リポジトリの作り方や Azure Pipelines についての説明は割愛します。
1. Docker CLIをインストールする
- task: DockerInstaller@0 inputs: dockerVersion: '17.09.0-ce' displayName: 'Install Docker'
2. サンプルアプリケーションを起動する
自分がテストしたいアプリケーションを起動してください。 すでに起動しているサービスに対してテストする場合は、このタスクは不要です。
- task: Bash@3 inputs: targetType: 'inline' script: | docker run --rm -p 80:80 --detach yeasy/simple-web:latest displayName: 'Run Sample Application'
3. ZAP Dockerを実行する
ZAP を起動して対象サイトに 攻撃しています。
-t http://$(ip -f inet -o addr show docker0 | awk '{print $4}' | cut -d '/' -f 1)
の部分をテストしたいところに変更しましょう。
なお、攻撃権限がないサイトを設定しないでください。
末尾の true
は Azure Pipelines の Bashタスクの仕様上 成功ステータスにするため追加しています。
- task: Bash@3 inputs: targetType: 'inline' script: | chmod -R 777 ./ docker run --rm -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable zap-full-scan.py -t http://$(ip -f inet -o addr show docker0 | awk '{print $4}' | cut -d '/' -f 1) -r report.html true displayName: 'Run ZAP Scan'
4. ZAP レポートをpublishする
- task: PublishPipelineArtifact@1 inputs: targetPath: '$(Build.SourcesDirectory)/report.html' publishLocation: 'pipeline' displayName: 'Publish Report'
5. azure-pipelines.yml
全体としてはこんな感じです。
trigger: none stages: - stage: Test jobs: - job: Build pool: vmImage: 'ubuntu-20.04' steps: - task: DockerInstaller@0 inputs: dockerVersion: '17.09.0-ce' displayName: 'Install Docker' - task: Bash@3 inputs: targetType: 'inline' script: | docker run --rm -p 80:80 --detach yeasy/simple-web:latest displayName: 'Run Sample Application' - task: Bash@3 inputs: targetType: 'inline' script: | chmod -R 777 ./ docker run --rm -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable zap-full-scan.py -t http://$(ip -f inet -o addr show docker0 | awk '{print $4}' | cut -d '/' -f 1) -r report.html true displayName: 'Run ZAP Scan' - task: PublishPipelineArtifact@1 inputs: targetPath: '$(Build.SourcesDirectory)/report.html' publishLocation: 'pipeline' displayName: 'Publish Report'
6. CIが完了して結果をダウンロードするとZAPのレポートを確認できます。
レポートはこんな感じです。
まとめ
ZAP Docker は、導入がシンプルなのでセキュリティ診断してみようくらいのモチベーションのときにおすすめです。 Azure Pipelines では OWASP Zed Attack Proxy Scan
というタスクを用いるパターンもありますが
オプションで柔軟に設定を変更したい場合は、Dockerがおすすめですし、ローカル環境でも動作を確認しやすいです。
また、API Scanは実行に時間がかかるため CIに不向きだと思いますが Baseline Scan や 時間をチューニングした Full Scan は継続的に実行することで問題を早めに検知できます。
なお、今回の手順ではレポートをダウンロードして確認するパターンにですが、それだと確認するのが大変なため レポートを Azure Pipelines で確認できる形式に変換するのが便利かもしれません。こちらの変換の仕方は 実践したらまた記事にしようと思います。