はじめに
Credential Stuffing 対策の一つとして Cloudflare WAF 機能の一つである Exposed Credentials Check を紹介します。
Credential Stuffing について
Credential Stuffing は、あるサービスで漏洩した認証資格情報を使い、他のサービスでログイン試行することを指します。認証資格情報は使い回されがちなので、そこが狙われます。
自分のユーザー名やパスワードがどこかに漏れてるんじゃないかと "Have I Been Pwned” などで確認される方もいらっしゃるのではないでしょうか。
そのようなサイトでは、これまでに漏洩した認証資格情報がデータベース化されており、ユーザーは自分(あるいは他の誰か)に関連したユーザー名やパスワードがそこに含まれるかを確認することができます。
HIBP には最近の情報漏洩と思われるデータも既に含まれていそうです。
「光回線サービスの東名に不正アクセス、顧客情報の一部流出の可能性」
なお、Cloudflare もデモサイト MIGP "Might I Get Pwned" を公開しています。
背景 Blog
Cloudflare Proxy での対策と Exposed Credentials Check
Cloudflare Proxy を Eyeball と Web アプリケーションの間にオンパス(on-path)で入れることで、この種の攻撃緩和に使うことができます。
その中の一つが Exposed Credentials Check です。
プロダクトの例 | 内容 |
---|---|
Open Proxy managed List | 攻撃の踏み台に利用されている Open Proxy のリストを参照し、そこからのリクエストを制御 |
Bot Management / Super Bot Fight Mode | ボットスコアリングにより、ボットらしいリクエストを制御 |
Exposed Credential Checks | 公に漏洩しているユーザー名/パスワードの情報とリクエストの入力値を照合 |
Rate Limiting on failed logins | ログイン失敗のイベントを観測し、しきい値以上のリクエストを制御 *ログイン失敗時にオリジンサーバーが任意のレスポンスヘッダーやステータスコード(4xxなど)で状況を伝えてくれれば追随できる |
Cloudflare Access Managed Devices | 自組織で管理されたデバイスからのリクエストのみを許可 |
前提:Exposed Credentials Check とプライバシー保護
ユーザー名とパスワードは超機密情報です。
Exposed Credentials Check では、プライバシー保護に対するアプローチとして、これらの情報が WAF 以外のプロセスにさらされない、また、データベースとの照合はハッシュをもってやり取りされる、といった対策が実装されています。
どのようなアプリケーションのログインページに対応しているか
本家にリストがありますが、API でも Description と Categories がとれますので、それを記します。
"各アプリケーションのログインページ"および"汎用的なログインページ"への対応が可能です。
Description | Categories | Action (default) |
---|---|---|
Blocks requests containing 'Exposed-Credential-Check' headers, as these can be used to trick the origin into believing a request contained (or didn't contain) an exposed credential | header | block |
Checks credentials from the default drupal login page | drupal | rewrite |
Checks credentials in POST forms using "username" and "password" arguments | application-multi | rewrite |
Checks credentials in POST forms using "login" and "password" arguments (URI agnostic) | application-multi | rewrite |
Checks credentials from the default ghost login page | ghost | rewrite |
Checks credentials from the default joomla login page | joomla | rewrite |
Checks credentials from the default magento login page | magento | rewrite |
Checks credentials from the default plone login page | plone | rewrite |
Checks credentials from the default wordpress login page | wordpress | rewrite |
Checks credentials sent as JSON with 'email' and 'password' keys | application-multi | rewrite |
Checks credentials sent as JSON with 'username' and 'password' keys | application-multi | rewrite |
Beta rule 3 | application-multi | rewrite |
Beta rule 4 | application-multi | rewrite |
Checks Microsoft Exchange OWA credentials | microsoft-exchange-owa | rewrite |
四番目の form login の Description に URI agnostic とあるのは 三番目の form username のほうに対象の URI が暗に定義されているためです。
form login や JSON は URI に関わらずマッチします。
取得例
$ curl -s -X GET -H "Content-Type: application/json" -H "X-Auth-Email: $EMAIL" -H "X-Auth-Key: $API_KEY" "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/$RULESET"|jq -r '.result.rules[]|[.description, .categories[], .action]|@tsv'
Blocks requests containing 'Exposed-Credential-Check' headers, as these can be used to trick the origin into believing a request contained (or didn't contain) an exposed credential header block
Checks credentials from the default drupal login page drupal rewrite
Checks credentials in POST forms using "username" and "password" arguments application-multi rewrite
Checks credentials in POST forms using "login" and "password" arguments (URI agnostic) application-multi rewrite
Checks credentials from the default ghost login page ghost rewrite
Checks credentials from the default joomla login page joomla rewrite
Checks credentials from the default magento login page magento rewrite
Checks credentials from the default plone login page plone rewrite
Checks credentials from the default wordpress login page wordpress rewrite
Checks credentials sent as JSON with 'email' and 'password' keys application-multi rewrite
Checks credentials sent as JSON with 'username' and 'password' keys application-multi rewrite
Beta rule 3 application-multi rewrite
Beta rule 4 application-multi rewrite
Checks Microsoft Exchange OWA credentials microsoft-exchange-owa rewrite
ユーザー名とパスワードの入力フィールド名
各アプリケーション向けのルールについては、ログインで利用されるユーザー名とパスワードのフィールド名がそれぞれ定義されています。
その他、汎用的なログイン情報入力フィールドとして、下記のルールが定義されています。
- Check forms submitted using a POST request containing username and password arguments
- Check credentials sent as JSON with email and password keys
- Check credentials sent as JSON with username and password keys
メソッド | 入力形式 | content-type | ユーザー名のフィールド名 | パスワードのフィールド名 |
---|---|---|---|---|
POST | フォーム | application/x-www-form-urlencoded | username | password |
POST | フォーム | application/x-www-form-urlencoded | login | password |
POST | JSON | application/json | password | |
POST | JSON | application/json | username | password |
フォームの login については devdoc に記載がないですが、API のレスポンスには明記されているので入れてます。
Action(検知された場合の挙動)
検知された場合の Action については、Exposed-Credential-Check Header, Managed Challenge, Block, JS Challenge, Log, and Interactive Challenge が使えます。
漏洩情報が使用されたことをオリジンサーバに示すため、リクエストヘッダーに Exposed-Credential-Check を追加するのがデフォルトです。
オリジンサーバー側で何かしらの対応ができるようになります。
設定
Zone レベルで設定をします。
Zone の WAF > Managed rules から "Cloudflare Leaked Credentials Check" を Enabled にします。
すべてのリクエストがこの Ruleset で評価され始めます。
設定をデフォルトから変更する場合は青字の名前部分をクリック(または右のミートボールから Edit を選択)し、変更画面に遷移します。
他の Managed Ruleset と同じ手順ですね。
今回はデフォルトで行きます。
使用例
テスト用のダミーのユーザー名とパスワードがありますので、そちらを試します。
key | value |
---|---|
username | CF_EXPOSED_USERNAME@example.com |
password | CF_EXPOSED_PASSWORD |
username1@example.com
password1
も使えました。
Eyeball
curl -s 'https://www2.oyama.cf/login' -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'login=CF_EXPOSED_USERNAME%40example.com&password=CF_EXPOSED_PASSWORD'
オリジンサーバー
オリジンサーバーが受信したリクエストヘッダーには Exposed-Credential-Check が 1 でセットされています。
Exposed-Credential-Check: 1
マッチしない場合はヘッダー自体がセットされません。
観測
Security Events ダッシュボードで簡単にイベント発生状況を得ることができます。
どれくらい Leaked Password を使ったログインが施行されたか、わかりますね。
個別のイベントをみると、一つ一つのイベントの詳細がわかります。
- Service: Managed rules
- Ruleset: Cloudflare Exposed Credentials Check Ruleset
- Rule: Checks credentials in POST forms using "username" and "password" arguments
- Action taken: Rewrite
通知
WAF の一部なので、イベントのスパイク時には Notification の機能で通知することができます。
この状況では 260 を越えたあたりで Slack に通知が来ました。
ログ
HTTP Requests あるいは Firewall Events で取ることができます。
Firewall Events で Payload logging を有効にしている場合、Event ログに暗号化された Payload データが追加されます。
フォームの場合、そのデータを復号化すると、下記のようにユーザ名/パスワードが確認できます。JSON ではユーザー名/パスワードは含まれません。
{
"http.request.method": "POST",
"http.request.headers": {
"accept": [
"*/*"
],
"content-length": [
"68"
],
"content-type": [
"application/x-www-form-urlencoded"
],
"host": [
"www2.oyama.cf"
],
"user-agent": [
"curl/8.2.1"
],
"x-forwarded-proto": [
"https"
]
},
"http.request.body.form": {
"login": [
"CF_EXPOSED_USERNAME%40example.com"
],
"password": [
"CF_EXPOSED_PASSWORD"
]
}
}
ユーザ名とパスワードが表示されるのでドキッとしますが、 Payload logging はそもそもプライバシー保護のための技術なので、ここで見えているユーザ名とパスワードは秘密鍵を持つユーザー管理者のみが閲覧できます。
中締め
以上 Zone レベルでの Exposed Credentials Check の設定および動作概要でした。
以降は Zone レベルの挙動では足りない場合の Account レベルでの設定を紹介します。
*Account level WAF が必要になります。
Account レベル WAF(Managed / Custom Rulesets)での Exposed Credeintials Check 対応
Zone レベルでの Exposed Credentials Check で足りない場合があります。
たとえば下記のようなケースです。
これらに対しては Account level WAF の Managed / Custom Rulesets で対応します。
番号 | ユースケース | 対応する Ruleset (Account level) |
Phase |
---|---|---|---|
1 | Exposed Credentials Check の Managed ruleset に対象アプリケーションがない、または、ユーザー名/パスワードの入力フィールドをデフォルトから変えたい。 また、特定のホストやパスを対象にしたい。 |
Custom ruleset | http_request_firewall_custom |
2 | Exposed Credentials Check の Rule は Managed ruleset で足りるが、特定の Zone 、ホスト、パスだけ Exposed Credentials Check の対象にしたい。 | Managed ruleset | http_request_firewall_managed |
3 | Exposed Credentials Check の Rule は Managed ruleset で足りるが、Account 全体に共通の Exposed Credentials Check を仕込みたい。 | Managed ruleset | http_request_firewall_managed |
Account レベル WAF の設定画面を見ると、Custom rulesets と Managed rulesets それぞれの設定タブが用意されています。
ただ、上記のケース 1 の Exposed Credentials Check の Custome Rules についてはダッシュボードでの設定が現時点ではサポートされていないので API から定義します。
今回は 1 のケースに実際に対応してみます。
Exposed Credentials Check 用 Custom Ruleset 設定例
対象のアプリケーションは下記の仕様だとします。
入力形式 | ユーザー名のフィールド名 (username_expression) |
パスワードのフィールド名 (password_expression) |
パス (expression) |
---|---|---|---|
JSON | onamae | passwd | /my-login |
Custom Ruleset を使い、これに対応する Exposed Credentials Check を仕込むことになります。
Custom Ruleset データ(JSON)の準備
リクエエストのマッチ条件と、マッチした際のアクションを定義します。
下記のような内容で Ruleset 設定用の JSON データを作ります。
この場合、Ruleset に含まれる Rule は一つですが、複数入れることもできます。
Ruleset | value |
---|---|
phase | http_request_firewall_custom |
name | Custom Ruleset A |
description | This ruleset includes a rule checking for exposed credentials. |
kind | custom |
rules | 個々の Rule が入る ⇓ |
Rule | value | 備考 |
---|---|---|
expression | http.request.method == "POST" && http.request.uri == "/my-login" && any(http.request.headers["content-type"][*] == "application/json") | リクエストをこのルールにマッチさせるための表現。 ここでは method,uri,content-typeを定義 |
action | rewrite | |
action_parameters | header Exposed-Credential-Check に 1 をset | rewrite の具体的な内容 |
exposed_credential_check | "username_expression": lookup_json_string(http.request.body.raw, "onamae") "password_expression": lookup_json_string(http.request.body.raw, "passwd") |
リクエストからユーザ名とパスワードを入手するための表現。 onamae と passwd というフィールド名(JSON Key)を探す |
description | Exposed credential check on my-login endpoint with JSON body |
{
"name": "Custom Ruleset A",
"kind": "custom",
"description": "This ruleset includes a rule checking for exposed credentials.",
"rules": [
{
"action": "rewrite",
"action_parameters": {
"headers": {
"Exposed-Credential-Check": {
"operation": "set",
"value": "1"
}
}
},
"description": "Exposed credential check on my-login endpoint with JSON body",
"expression": "http.request.method == \"POST\" && http.request.uri == \"/my-login\" && any(http.request.headers[\"content-type\"][*] == \"application/json\")",
"exposed_credential_check": {
"username_expression": "lookup_json_string(http.request.body.raw, \"onamae\")",
"password_expression": "lookup_json_string(http.request.body.raw, \"passwd\")"
}
}
],
"phase": "http_request_firewall_custom"
}
Custom Ruleset の作成
このデータを Account の ruleset エンドポイントに対して POST することで、ruleset を作成することができます。
→ create ruleset
$ curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/rulesets" \
--header 'X-Auth-Email: '$EMAIL'' --header 'X-Auth-Key: '$API_KEY'' --header 'Content-Type: application/json' --data '@rulesetA' -s| jq '.'
作成がうまく行き、応答で下記の追加情報を得ました。
- Ruleset
Ruleset | value | 備考 |
---|---|---|
id | ef8cfa59128e4d669d7b90056ca8dab7 | 今後 Ruleset を 操作(Update など)するときに使う |
source | firewall_custom | |
version | 1 | Update するたびに増える |
last-updated | 2023-11-04T08:28:25.787328Z | Rulesetの最終更新日時 |
- Rule
Rule | value | 備考 |
---|---|---|
id | f75fcd3230fe42ae8a5c144404283e18 | 今後 Rule を 操作(Update など)するときに使う |
version | 1 | Update するたびに増える |
enabled | true | POST 時に指定しなければデフォルト true |
last-updated | 2023-11-04T08:28:25.787328Z | Ruleの最終更新日時 |
Ruleset, Rule それぞれが ID とバージョンで識別されていることがわかります。
{
"result": {
"id": "ef8cfa59128e4d669d7b90056ca8dab7",
"name": "Custom Ruleset A",
"description": "This ruleset includes a rule checking for exposed credentials.",
"source": "firewall_custom",
"kind": "custom",
"version": "1",
"rules": [
{
"id": "f75fcd3230fe42ae8a5c144404283e18",
"version": "1",
"action": "rewrite",
"exposed_credential_check": {
"username_expression": "lookup_json_string(http.request.body.raw, \"onamae\")",
"password_expression": "lookup_json_string(http.request.body.raw, \"passwd\")"
},
"expression": "http.request.method == \"POST\" && http.request.uri == \"/my-login\" && any(http.request.headers[\"content-type\"][*] == \"application/json\")",
"description": "Exposed credential check on my-login endpoint with JSON body",
"last_updated": "2023-11-04T08:28:25.787328Z",
"ref": "f75fcd3230fe42ae8a5c144404283e18",
"enabled": true,
"action_parameters": {
"headers": {
"Exposed-Credential-Check": {
"operation": "set",
"value": "1"
}
}
}
}
],
"last_updated": "2023-11-04T08:28:25.787328Z",
"phase": "http_request_firewall_custom"
},
"success": true,
"errors": [],
"messages": []
}
補足:Ruleset アップデート
設定済のデータをアップデートしたい場合は新しいデータを PUT します。
expression を下記のように変更してアップデートしてみます。
*パス /my-login を削除(追って別の場所で指定するため冗長回避)
Before | After |
---|---|
http.request.method == "POST" && http.request.uri == "/my-login" && any(http.request.headers["content-type"][*] == "application/json") | http.request.method eq "POST" and any(http.request.headers["content-type"][*] eq "application/json") |
$ curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/rulesets/$RULESET_ID" \
--header 'X-Auth-Email: '$EMAIL'' --header 'X-Auth-Key: '$API_KEY'' --header 'Content-Type: application/json' -data '@rulesetA' -X PUT| jq '.'
戻りデータではバージョンが上がっています。
"version": "2",
"rules": [
{
:
"expression": "http.request.method eq \"POST\" and any(http.request.headers[\"content-type\"][*] eq \"application/json\")",
:
Custom Ruleset のデプロイ
この時点ではまだ Ruleset はリクエストに反映されません。
作成された Ruleset のデプロイが必要になります。
API でデプロイするには Entry point Ruleset を action: execute で作成する必要があります。
Entry point ruleset(action: execute)について下の図で説明します。
- オレンジ枠、黒枠、どちらも Ruleset を表します(その中に Rule が複数あります "R1,R2,..")。
- 先に作成した Exposed Credentials Check 用の Custom Ruleset は黒枠に位置します。
- オレンジ枠が Entry point ruleset で、これから作ります。
- オレンジ枠の Ruleset を作り、その Rule の一つを黒枠の Ruleset に紐つけることで、黒枠 Ruleset が有効になります。
- リクエストがオレンジ枠に定義された Rule の expression にリクエストをマッチすると、紐付けられた Managed Rulesets または Custom Rulesets が Execute されます。(Entry point ruleset からみると Manage Ruleset や Custom Rulset は Rule 要素になります。)
- リクエストは Expression にマッチする限りそれぞれの処理を受けます。
"For a given incoming request, the expression of the first two rules matches the request properties. Therefore, the action for these rules runs (Execute and Log, respectively). "
- 同一 Phase 内で Field value は immutable で、Phase 内で変更されていても後続の Rule では参照されません。別の Phase に渡ると変っていることがあります。
”While evaluating rules for a given request/response, the values of all request and response fields are immutable within each phase. However, field values may change between phases."
Entry point ruleset 現状確認(デプロイ前)
http_request_firewall_custom フェーズの Account レベルで Entry point ruleset(オレンジ枠相当)を取ってみます。
entry point ruleset が見つからないと言われます。Ruleset が Deploy されていない状態です。
フェーズ | レベル | entry point ruleset |
---|---|---|
http_request_firewall_custom | account | Deployされてない |
$ curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/rulesets/phases/http_request_firewall_custom/entrypoint" \
--header 'X-Auth-Email: '$EMAIL'' --header 'X-Auth-Key: '$API_KEY'' --header 'Content-Type: application/json' -s
{
"result": null,
"success": false,
"errors": [
{
"message": "could not find entrypoint ruleset in the http_request_firewall_custom phase"
}
],
"messages": null
}
これを Deploy します。
Entry point ruleset データ(JSON)の準備
オレンジ枠にあたる Entry point ruleset として下記のようなデータを準備します。
{
"rules": [
{
"action": "execute",
"action_parameters": {
"id": "ef8cfa59128e4d669d7b90056ca8dab7"
},
"expression": "(http.host eq \"www2.oyama.cf\" and http.request.uri.path eq \"/my-login\")",
"description": "Routing condition for an accont level exposed credentials check"
}
]
}
Rule | value | 備考 |
---|---|---|
action | execute | Entry point ruleset から Ruleset を呼び出し |
action_parameters | ef8cfa59128e4d669d7b90056ca8dab7 | 呼び出す Ruleset("Custom Ruleset A")の ID |
expression | (http.host eq "www2.oyama.cf" and http.request.uri.path eq "/my-login") | リクエストをこのルールにマッチさせるための表現 # host と URI.path を指定 |
*呼び出したい Ruleset ID は API で確認できます。
$ curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/rulesets" \
--header 'X-Auth-Email: '$EMAIL'' --header 'X-Auth-Key: '$API_KEY'' --header 'Content-Type: application/json' -s | jq -r '.result[]|select(.name=="Custom Ruleset A")|.id'
ef8cfa59128e4d669d7b90056ca8dab7
Entry point ruleset の作成
Entry point ruleset(オレンジ枠相当)は PUT で配置します。
無事に作成されれば、ホスト名とパスにマッチするリクエストに対して Exposed Credentials Check の Custom Ruleset(黒枠相当)が呼び出されます。
$ curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/rulesets/phases/http_request_firewall_custom/entrypoint" \
--header 'X-Auth-Email: '$EMAIL'' --header 'X-Auth-Key: '$API_KEY'' --header 'Content-Type: application/json' -s -d '@ruleset.deploy' -X PUT
応答は下記のとおりです。
{
"result": {
"id": "8ff668a4e30b4c80869ae9d7c32ed0f7",
"name": "default",
"description": "",
"source": "firewall_custom",
"kind": "root",
"version": "5",
"rules": [
{
"id": "ff86ee0ce7e14a479cf98ea1aa3b7f91",
"version": "1",
"action": "execute",
"expression": "(http.host eq \"www2.oyama.cf\" and http.request.uri.path eq \"/my-login\")",
"description": "Routing condition for an accont level exposed credentials check",
"last_updated": "2023-11-04T12:05:07.282139Z",
"ref": "ff86ee0ce7e14a479cf98ea1aa3b7f91",
"enabled": true,
"action_parameters": {
"id": "ef8cfa59128e4d669d7b90056ca8dab7",
"version": "latest"
}
}
],
"last_updated": "2023-11-04T12:05:07.282139Z",
"phase": "http_request_firewall_custom"
},
"success": true,
"errors": [],
"messages": []
}
無事に配置できました。
動作確認 Account レベル Custom Ruleset(Exposed Credentials Check)
マッチするリクエストを投げると、ヘッダーに Exposed-Credential-Check: 1 が追加されていることがわかります。
$ curl -s 'https://www2.oyama.cf/my-login' -X POST -H 'Content-Type: application/json' --data-raw '{"onamae":"CF_EXPOSED_USERNAME@example.com","passwd":"CF_EXPOSED_PASSWORD"}' | jq '.'
{
:
"content-type": "application/json",
"Exposed-Credential-Check": "1",
"CDN-Loop": "cloudflare",
:
}
条件にマッチさせないリクエストにすると(onamae を username に変更)、ヘッダーが入りません。
$ curl -s 'https://www2.oyama.cf/my-login' -X POST -H 'Content-Type: application/json' --data-raw '{"username":"CF_EXPOSED_USERNAME@example.com","passwd":"CF_EXPOSED_PASSWORD"}' | jq '.'
{
:
"content-type": "application/json",
"CDN-Loop": "cloudflare",
:
}
余談:Zone の Exposed Credentials Check との兼ね合い
Phase の説明を見ると各 Phase で Account-level のあとに Zone-level が評価されます。
なので、exposed_credential_check が http_request_firewall_managed フェーズの Zone レベルで再度評価されると不都合がでてくる場合は Zone での設定は停止し Account の方に寄せるのがいいでしょう。
また、同時稼働させる場合は処理の流れに注意します。
各 Phase の評価順序は下記のとおりです(custom のあとに managed)。
phase | level | Exposed Credentials Check |
---|---|---|
http_request_firewall_custom | account | ✓ |
http_request_firewall_custom | zone | -なし- |
http_request_firewall_managed | account | ✓ |
http_request_firewall_managed | zone | ✓ |
また、Exposed Credeintials Check のみ抜き出し、図にしてみました。
*備考
Zone レベル 唯一のデフォルト Block ルール である
Blocks requests containing 'Exposed-Credential-Check' headers, as these can be used to trick the origin into believing a request contained (or didn't contain) an exposed credential"
の影響が気になりましたが、Account レベル の Custom Rules で追加した Exposed-Credential-Check ヘッダーは Block の対象とならないようで、止められることはありませんでした。
一方、Eyeball で Exposed-Credential-Check ヘッダーを付けたリクエストは、そのルールでブロックされました。
ダッシュボード
API で一連の設定が終わるとダッシュボードの Account level WAF にも設定が表示されましたが、一部反映されていないものもあるので、サポートされるまでは API での操作が無難と思います。
遊び
- ヘッダーを変えて Update
Rewrite 時、他のヘッダー名や値は受け入れられるか?
"action_parameters": {
"headers": {
"Ex-Cr-Ch": {
"operation": "set",
"value": "111111111111"
}
}
},
エラーで失敗
# Header名は Exposed-Credential-Check だけしけ入れられない
{
"result": null,
"success": false,
"errors": [
{
"code": 20139,
"message": "for rules using 'exposed_credential_check', you may only rewrite the 'Exposed-Credential-Check' header",
"source": {
"pointer": "/rules/0/action_parameters/headers"
}
}
],
"messages": null
}
# 値も 1 だけしけ入れられない
{
"result": null,
"success": false,
"errors": [
{
"code": 20139,
"message": "for rules using 'exposed_credential_check', you must set the 'value' field to '1'",
"source": {
"pointer": "/rules/0/action_parameters/headers"
}
}
],
"messages": null
}
補足
Zone レベルの ruleset
$ curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/phases/http_request_firewall_managed/entrypoint" \
--header 'X-Auth-Email: '$EMAIL'' --header 'X-Auth-Key: '$API_KEY'' --header 'Content-Type: application/json' -s | jq '.result.rules[]|select(.action_parameters.id=="'$RULESET_ID'")'
{
"id": "641f6b64ee1a4003b1bcdee81a9e823f",
"version": "15",
"action": "execute",
"expression": "true",
"description": "zone",
"last_updated": "2023-11-05T07:14:32.874846Z",
"ref": "641f6b64ee1a4003b1bcdee81a9e823f",
"enabled": true,
"action_parameters": {
"id": "c2e184081120413c86c3ab7e14069605",
"version": "latest",
"matched_data": {
"public_key": "*"
}
}
}
$ RULESET_ID=`curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets" \
--header 'X-Auth-Email: '$EMAIL'' --header 'X-Auth-Key: '$API_KEY'' --header 'Content-Type: application/json' -s | jq '.result[]|select (.name|contains ("Expose")).id' -r`
$ curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/$RULESET_ID" \
--header 'X-Auth-Email: '$EMAIL'' --header 'X-Auth-Key: '$API_KEY'' --header 'Content-Type: application/json' -s
{
"result": {
"id": "c2e184081120413c86c3ab7e14069605",
"name": "Cloudflare Exposed Credentials Check Ruleset",
"description": "Exposed credentials check rules",
"source": "firewall_managed",
"kind": "managed",
"version": "86",
"rules": [
{
"id": "ef21b0a932ae422790f9249d213b85e6",
"version": "83",
"action": "block",
"categories": [
"header"
],
"description": "Blocks requests containing 'Exposed-Credential-Check' headers, as these can be used to trick the origin into believing a request contained (or didn't contain) an exposed credential",
"last_updated": "2023-06-15T17:59:49.614653Z",
"ref": "2be7739490d648e8f217d5cf02caf47c",
"enabled": true
},
:
:
まとめ
Exposed Credeintials Check の設定について書きました。
API での設定が必須だったため Ruleset の記載が増えてしいましたが、そちらは改めて書こうと思います。
参考リンク
https://migp.cloudflare.com/
https://blog.cloudflare.com/privacy-preserving-compromised-credential-checking/
https://blog.cloudflare.com/account-takeover-protection/
https://developers.cloudflare.com/waf/managed-rules/reference/exposed-credentials-check/
https://developers.cloudflare.com/ruleset-engine/reference/phases-list/
https://haveibeenpwned.com/