LoginSignup
1
0

Cloudflare で Credential Stuffing 対策(Exposed Credentials Check 編)

Posted at

はじめに

Credential Stuffing 対策の一つとして Cloudflare WAF 機能の一つである Exposed Credentials Check を紹介します。

Credential Stuffing について

Credential Stuffing は、あるサービスで漏洩した認証資格情報を使い、他のサービスでログイン試行することを指します。認証資格情報は使い回されがちなので、そこが狙われます。
alt

自分のユーザー名やパスワードがどこかに漏れてるんじゃないかと "Have I Been Pwned” などで確認される方もいらっしゃるのではないでしょうか。

そのようなサイトでは、これまでに漏洩した認証資格情報がデータベース化されており、ユーザーは自分(あるいは他の誰か)に関連したユーザー名やパスワードがそこに含まれるかを確認することができます。
alt
alt

HIBP には最近の情報漏洩と思われるデータも既に含まれていそうです。
光回線サービスの東名に不正アクセス、顧客情報の一部流出の可能性
alt
alt

なお、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 email 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 で評価され始めます。

alt

設定をデフォルトから変更する場合は青字の名前部分をクリック(または右のミートボールから Edit を選択)し、変更画面に遷移します。
alt

他の 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 を使ったログインが施行されたか、わかりますね。

alt

個別のイベントをみると、一つ一つのイベントの詳細がわかります。

  • Service: Managed rules
  • Ruleset: Cloudflare Exposed Credentials Check Ruleset
  • Rule: Checks credentials in POST forms using "username" and "password" arguments
  • Action taken: Rewrite
alt

通知

WAF の一部なので、イベントのスパイク時には Notification の機能で通知することができます。
alt

この状況では 260 を越えたあたりで Slack に通知が来ました。
alt

ログ

HTTP Requests あるいは Firewall Events で取ることができます。

Firewall Events で Payload logging を有効にしている場合、Event ログに暗号化された Payload データが追加されます。
フォームの場合、そのデータを復号化すると、下記のようにユーザ名/パスワードが確認できます。JSON ではユーザー名/パスワードは含まれません

payload 例(フォーム)
{
  "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 rulesetsManaged rulesets それぞれの設定タブが用意されています。
alt

ただ、上記のケース 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
rulesetA: Ruleset 設定用データ
{
  "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

作成用 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' --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 します。

update ruleset

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")
作成用 API
 $ 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)について下の図で説明します。

alt
  • オレンジ枠、黒枠、どちらも 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 として下記のようなデータを準備します。

デプロイ用の Body
{
  "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 で確認できます。

Ruleset ID を 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' -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 が評価されます。

alt

なので、exposed_credential_check が http_request_firewall_managed フェーズの Zone レベルで再度評価されると不都合がでてくる場合は Zone での設定は停止し Account の方に寄せるのがいいでしょう。
また、同時稼働させる場合は処理の流れに注意します。
alt

各 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 での操作が無難と思います。

alt alt alt alt

遊び

  • ヘッダーを変えて 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

http_request_firewall_managed の zone の entry point ruleset(の中の Exposeed Credentials Check 呼び出し用の Rule)
$ 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": "*"
    }
  }
}
http_request_firewall_managed の zone の ruleset(Exposeed Credentials Check の Ruleset)

$ 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/

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0