【OWASP ZAP】認証設定 (1) Form認証、ベーシック認証のわかりづらいところ

# はじめに
OWASP ZAPを使用し、いくつかのログインの必要なサイトに対して診断を実施しました。
公式のドキュメントを見ても、どのように設定したらいいのか、実際の挙動がどうなるのか、わかりづらい部分が結構ありました。そうしたところを記事にまとめてみようと思います。
今回はZAPの認証設定「Form-Based Authentication」「JSON-Based Authentication」「HTTP/NTLM Authentication」について書きます。

次回以降、ユーザーが作成したスクリプトを使用できる「Script-Based Authentication」やユーザー名・パスワード以外設定不要な「Auto-Detect Authentication」について書く予定です。
また、Automation Frameworkやクロールしにくいサイトに対するSpider, Ajax Spider等を工夫して行う方法もまとめていきたいと考えています。

[【OWASP ZAP】認証設定 (2) ログインスクリプトの作り方。Dockerでのスクリプト利用方法](https://qiita.com/Shcb8Qyoj021/items/2fa5377bb6105b9817fd)

本記事内で触れていない、インストールから設定、スパイダー、診断の基本的な方法は下記ページがわかりやすかったです。

[はじめに｜脆弱性診断入門（OWASP ZAP編）](https://zenn.dev/hideoamezawa/books/study_owasp_zap/viewer/1_start)

# 目次
- 共通して設定必要な項目
    - Authentication Verification
    - Dockerで診断するときの工夫
- Form-Based Authentication
- JSON-Based Authentication
- HTTP/NTLM Authentication

# 動作環境
- ZAP GUI: 2.15.0
- Docker Image: zaproxy/zap-stable:20240902

# 共通して設定必要な項目
## Authentication Verification
Authentication Verificationは認証が必要なサイトを診断中に、OWASP ZAPのスキャナが現在ログインできているかを確認する方法を設定する項目です。ログインできていない場合には再認証を行います。

[公式ドキュメント - Authentication Verification Strategies](https://www.zaproxy.org/docs/desktop/start/features/authstrategies/)

設定した認証方法でログインに成功したかどうかは、GUIのアウトプットの項目で確認でき、「ログインに成功しました」や「ログインに失敗しました」と表示されます。
OWASP ZAP内に保存されているAuthentication Statisticsの値でも確認でき、ZAPのAPIを利用することでAuthentication Statisticsの値を取得できます。

[ZAP – Authentication Statistics](https://www.zaproxy.org/docs/desktop/addons/authentication-statistics/)
[statsViewStats – API Reference](https://www.zaproxy.org/docs/api/#statsviewstats)

Authentication Verificationは下記項目から選択できます。
- Check every Response
- Check every Request
- Check every Request or Response
- Poll the Specified URL
- Auto-Detect

### Check every Response、Check every Request、Check every Request or Response
「Logged In Indicator」または「Logged Out Indicator」を指定して、
ログイン・ログアウト時のレスポンスまたはリクエストのヘッダー・ボディに含まれている文字列からログイン・ログアウト状態を判別できるようになります。
（例）Logged In Indicator: ```\Q<a href="/logout">ログアウト</a>\E```

※「Logged In Indicator」、「Logged Out Indicator」ともに、文字列の頭に\Q、文字列の最後に\Eを入れて設定するみたいです。それらの文字列を挿入しなかった場合にも動くかもしれませんが、公式的には必要となっています。

### Poll the Specified URL
特定のURLを指定し、そのURLにアクセスした際のリクエストまたはレスポンス内に含まれる文字列からログイン・ログアウト状態を判別します。上記設定時と同様に「Logged In Indicator」、「Logged Out Indicator」を設定します。
サイト内のレスポンスで判別できないときに、ログイン状態を確認できるAPIのURL等を指定できます。

### Auto-Detect
上記の様に文字列等を設定しなくても、OWASP ZAPが自動的にログイン状態を検出してくれる設定のようで、2023年にリリースされたみたいです。実際どのように検出しているかはわからないですが、一般的な検出方法の場合は設定不要になるのではないか、と考えています。
（例）レスポンスのボディにlogout等の文字列が含まれている場合にログイン状態と判別する



## Dockerで診断するときの工夫
OWASP ZAPをDockerコンテナで起動して、API等で診断を実行するケースがあると思います。その場合、OWASP ZAPのGUIが見られないため、APIで得られるデータから判断する必要があります。
設定した認証情報でログインできたかどうかを早めに判別できるようにすることで、設定および診断にかかる時間を短くできます。
### APIでログインを判別する方法
- OWASP ZAPの内部に保存されている「stats.auth.component.state.loggedin」の値をAPIで取得し、０より大きいかを確認する
- スパイダーを実行し、実行結果を取得して、URLリストにログイン後でないとアクセスできないURLが含まれているか確認する
    - 「コンテキストに含まれるURL」設定で認証が必要なURLを1つ設定して、スパイダー実行することでかかる時間を短縮できます

# Form-Based Authentication
フォーム認証のあるサイトを診断できます。3項目以上の入力項目がある場合や、2画面認証（ユーザー名とパスワードを入力する画面が別）の場合は「Script-Based Authentication」で対応する必要があります。
CSRF対策のトークン等がある場合には、別途CSRF対策トークン名を設定することで、認証できます。

## 設定項目
- Login Form Target URL
ログイン時に認証情報を送信するURL（POSTメソッド）
- URL to GET Login Page
CSRF対策のトークンがある場合などに、上記Target URL送信前にアクセスするページ
- Login Request POST Data
ユーザー名のフィールド名とパスワードのフィールド名を設定する項目。設定の仕方がわかりづらいので注意する必要があります。
（例）ユーザー名のフィールド名が「username_field」、パスワードのフィールド名が「password_field」の場合
　　```username_field={%username%}&password_field={%password%}```
- Username Parameter
- Password Parameter
Username/Password Parameterは「Login Request POST Data」設定後に、{%~%}となっている項目から選択可能です。

# JSON-Based Authentication
認証をJSON形式のデータで行う場合に使用します。設定項目自体は「Form-Based Authentication」と同じです。
「Form-Based Authentication」が「name1=value1&name2=value2」という形式で認証情報を送信するのに対し、
こちらではJSONオブジェクトで送信します。
（例）```{"username": "{%username%}", "password":  "{%password%}"}```

# HTTP/NTLM Authentication
ベーシック認証、 ダイジェスト認証、NTLM認証で使用できます。
ホスト名、認証レルム、ポートを設定することで利用できます。認証レルムは指定しなくても認証に成功できた気がします。


本ポストで紹介しなかったけれど、認証が必要なサイトに診断する際に設定必要な項目は下記があります。それほどわかりづらくないと思います。
- コンテキストに含まれるURL
    診断対象とするURLを正規表現で設定する。ワイルドカード設定は「.*」で可能です。
    （例）```https://example.jp.*```
- セッション管理
下記項目から選択
    - Cookie-Based Session Management
        ログイン中か判別するために使用されるsession id等がcookieに保存されている場合
    - HTTP Authentication Session Management
        Authorizationヘッダーでログイン中か判別する場合
    - Script-Based Session Management
        上記2つで対応できない複雑なセッション管理をしている場合、スクリプトを自作することで対応することもできます。
    - Header-Based Session Management
        新しく追加されているが、ドキュメントに記載もなく詳細が不明です。
    - Auto-Detect Session Management
        新しく追加されているが、ドキュメントに記載もなく詳細が不明です。

- ユーザ
    認証時に使用するユーザー名、パスワードの設定をします。複数ユーザー登録可能です
- 強制ユーザ
    こちらの項目の仕様はあまりわからないのですが、選択したユーザーの認証情報がスパイダー、アクティブ診断時に使用されます

# おわりに
次回はログインスクリプトの作り方や使用例について記事を書く予定です。フォーム認証とベーシック認証が両方あるサイトや、selenium、local storageを使用する場合、cognitoで認証を行っているサイトに対応する方法などを予定しています。
Pythonでの実装例等も書けたらいいなと思ってます。