JWT検証の設定
Cloudflare APIを使用してJWT検証を設定します。これにはトークン設定とトークン検証ルールが必要です。
トークン設定は、クライアントから送信されたJSON Webトークン(JWT)を検証するために使用されるJSON Webキーセット(JWKs)を定義し、これらのJWTがリクエスト内でどこに送信されるかに関する情報を提供します。
トークン設定には以下の情報が必要です:
フィールド名 | 説明 | 例 | 注釈 |
|---|---|---|---|
title | 設定の目的を迅速に特定できる人間が読める名前です。 | 本番JWT設定 | 50文字以内に制限されています。 |
description | titleよりも詳細な人間が読める説明で、顧客が設定の使用をより良く文書化できる手段として機能します。 | この設定はエンドポイント管理のすべてのエンドポイントで使用され、認証ヘッダー内のJWTをチェックします。 | 500文字以内に制限されています。 |
token_sources | JWTがリクエスト内で見つかる可能性のある場所のリストです。 | http.request.headers[\"authorization\"][0] http.request.cookies[\"Authorization\"][0] | 以下の情報を参照してください。 |
token_type | 検証するトークンのタイプを指定します。 | jwt | 現在サポートされているのはjwtのみです。 |
credentials | JWTを検証するために使用されるべき暗号化された公開鍵を説明します。このフィールドはJSONウェブキーでなければなりません。 | 以下の例を参照してください。 | 以下の情報を参照してください。 |
各項目は、文字列に解決されるルールセットエンジンの式でなければなりません。
現在サポートされているフィールドはhttp.request.headersとhttp.request.cookiesです。
最大4つのトークンソースを設定できます。リクエストにこれらのフィールドが複数設定されている場合、1つだけが使用されます。リクエストトークン内の先頭のBearer: 文字列は自動的に無視されます。
ルールセットエンジンフィールドの操作に関する詳細は、ルールセットエンジンのドキュメントを参照してください。
API Shieldは、RS256、RS384、RS512、PS256、PS384、PS512、ES256、およびES384タイプの認証情報をサポートしています。RSAキーは少なくとも2048ビットでなければなりません。各JSONウェブキーには「KID」が必要で、JWTのヘッダーにも存在する必要があります。これにより、API Shieldがそれらを一致させることができます。
キーのロールオーバーを支援するために、最大4つの異なるキーを許可します。
Cloudflareは、各キーから不要なフィールドを削除し、サポートされていないキーを削除します。
API呼び出しの出力を検証して、結果のキーが意図した通りに表示されることを確認することを強くお勧めします。
以下の例は、Cloudflare APIを使用してトークン設定を作成するために必要なすべての情報を含むJSONオブジェクトを示しています。テスト用のJWKを作成したい場合は、mkjwk JSON Web Key Generator ↗を参照してください。
{ "title": "本番JWT設定", "description": "この設定は認証ヘッダーまたはクッキー内のJWTをチェックします。", "token_sources": [ "http.request.headers[\"authorization\"][0]", "http.request.cookies[\"Authorization\"][0]" ], "token_type": "jwt", "credentials": { "keys": [ { "kty": "EC", "use": "sig", "crv": "P-256", "kid": "93UrzmNu1mqXs5cZcvCPkTlMHB2Jya30vSTkiBb0vhU", "x": "QG3VFVwUX4IatQvBy7sqBvvmticCZ-eX5-nbtGKBOfI", "y": "A3PXCshn7XcG7Ivvd2K_DerW4LHAlIVKdqhrUnczTD0", "alg": "ES256" } ] }}cURLまたは他のAPIクライアントツールを使用して、新しい設定をCloudflareのAPIに送信してJWT検証を有効にします。{zone_id}を関連するゾーンIDに置き換え、認証情報ヘッダーを追加してください。
curl "https://api.cloudflare.com/client/v4/zones/{zone_id}/api_gateway/token_validation" \--header 'Content-Type: application/json' \--data '{ "title": "本番JWT設定", "description": "この設定は認証ヘッダーまたはクッキー内のJWTをチェックします。", "token_sources": [ "http.request.headers[\"authorization\"][0]", "http.request.cookies[\"Authorization\"][0]" ], "token_type": "jwt", "credentials": { "keys": [ { "kty": "EC", "use": "sig", "crv": "P-256", "kid": "93UrzmNu1mqXs5cZcvCPkTlMHB2Jya30vSTkiBb0vhU", "x": "QG3VFVwUX4IatQvBy7sqBvvmticCZ-eX5-nbtGKBOfI", "y": "A3PXCshn7XcG7Ivvd2K_DerW4LHAlIVKdqhrUnczTD0", "alg": "ES256" } ] }}'レスポンスはCloudflareのv4レスポンスエンベロープ内にあり、結果には作成された設定が含まれます。返されたIDに注意してください。これは、APIを使用してトークン検証ルールを作成する際にトークン設定を参照するために使用されます。
{ "result": { "id": "d5902294-00c3-4aed-b517-57e752e9cd58", "token_type": "JWT", "title": "本番JWT設定", "description": "この設定は認証ヘッダーまたはクッキー内のJWTをチェックします。", "token_sources": [ "http.request.headers[\"authorization\"][0]", "http.request.cookies[\"Authorization\"][0]" ], "credentials": { "keys": [ { "x": "QG3VFVwUX4IatQvBy7sqBvvmticCZ-eX5-nbtGKBOfI", "y": "A3PXCshn7XcG7Ivvd2K_DerW4LHAlIVKdqhrUnczTD0", "alg": "ES256", "crv": "P-256", "kid": "93UrzmNu1mqXs5cZcvCPkTlMHB2Jya30vSTkiBb0vhU", "kty": "EC" } ] }, "created_at": "2023-11-08T16:45:17.236841Z", "last_updated": "2023-11-08T16:45:17.236841Z" }, "success": true, "errors": [], "messages": []}トークン検証ルールを使用すると、既存のトークン設定を使用してセキュリティポリシーを強制できます。
トークン検証ルールは、Cloudflare APIまたはダッシュボードを使用して構成できます。
フィールド名 | 説明 | 例 | 注釈 |
|---|---|---|---|
title | 迅速に特定できる人間が読める名前です。 | v1およびv2.example.comでのJWT検証 | 50文字以内に制限されています。 |
description | titleよりも詳細な人間が読める説明で、文書化を助けます。 | 有効なauthorizationヘッダーのないリクエストをログに記録します。 | 500文字以内に制限されています。 |
action | expressionを満たさないリクエストに対して取られるファイアウォールアクション。 | log | 可能な値: logまたはblock |
enabled | ルールを有効または無効にします。 | true | 可能な値: trueまたはfalse |
expression | ルールのセキュリティポリシー。 | is_jwt_valid ("00170473-ec24-410e-968a-9905cf0a7d03") | Cloudflare APIを使用してルールを作成する際は、引用符をエスケープしてください。 詳細はセキュリティポリシーの定義を参照してください。 |
selector | このルールでカバーされる操作を構成します。 | 操作にルールを適用するを参照してください。 |
セレクターは、トークン検証ルールの範囲を制御します。
特定のホスト名やドメインのサブドメインでのみJWT検証が必要な場合は、セレクターにホスト名を使用してJWT検証ルールに含めます。
設計上、常に有効なJWTが使用されないエンドポイント(最初に有効なJWTを確立するために使用されるパスとメソッドなど)をJWT検証から除外する必要がある場合は、エンドポイントの操作IDを使用してセレクターで除外する必要があります。
操作IDを見つけるには、エンドポイント管理を参照するか、Cloudflare APIを使用してください。
トークン検証ルールの式は、リクエストが満たす必要があるセキュリティポリシーを定義します。
たとえば、式is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e") or is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e")は、受信リクエストに少なくとも1つの有効な認証トークンがない場合にトリガーされます。
これらの式は、ルールセットエンジンで使用される式に似ていますが、いくつかの重要な違いがあります:
- トークン検証ルールのアクションは、式が
falseと評価される場合にトリガーされます。これは、ルールセット式とは異なります。 - トークン検証ルールは、トークン設定を参照する専用の関数を使用できます。
or、and、eqなどの演算子は、ルールセットエンジンで使用される式と同様に、式内で使用できます。
リクエスト上のJWTトークンと対話するために使用できる関数は以下の通りです:
機能 | 説明 | ノート |
|---|---|---|
is_jwt_valid(token_configuration_id String) bool | token_configuration_idのIDを持つトークン設定に従ってリクエストが有効なトークンを持っている場合はTrueを返します。 | token_configuration_idは既存のトークン設定のIDでなければなりません。このトークンがリクエストに存在しない場合はfalseを返します。 |
is_jwt_present(token_configuration_id String) bool | token_configuration_idのIDを持つトークン設定に従ってリクエストがトークンを持っている場合はTrueを返します。 | token_configuration_idは既存のトークン設定のIDでなければなりません。 |
どのセキュリティポリシーを使用するかを理解するために、以下の例を参照してください。ほとんどの使用例では、CloudflareはAPI全体で有効なトークンを要求し、トークンを確立または更新するために使用されるパスを除外することを推奨します。
is_jwt_present("51231d16-01f1-48e3-93f8-91c99e81288e")の式は、リクエストにJWTが欠けている場合にアクションをトリガーします。
これは、認証ヘッダーが欠けているリクエストをログに記録するために、トークン検証ルールのlogアクションと組み合わせることができます。
is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e")の式は、リクエストに有効なJWTがない場合にアクションをトリガーします。
これは、無効な資格情報またはトークンがないリクエストをブロックするために、トークン検証ルールのblockアクションと組み合わせることができます。
is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e") or is_jwt_valid("fddfc39e-3686-4683-ab23-bf917da6bb43")の式は、リクエストに少なくとも1つの有効なトークンがない場合にアクションをトリガーします。
これは、JWKを複数のトークン設定に分割する必要がある場合に発生する可能性があります。
is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e") or not is_jwt_valid("51231d16-01f1-48e3-93f8-91c99e81288e")の式は、リクエストに無効なトークンがある場合にアクションをトリガーし、トークンが全くないリクエストは無視します。
1つのトークン検証ルールのみが操作に適用できます。操作が複数のルールに該当する場合、最も優先度の高いルールが適用されます。
selectorフィールドを使用して、JWT検証が強制される操作を構成できます。
例えば、以下のセレクターは、v1.example.comおよびv2.example.comのすべての操作にルールを適用しますが、これらのホスト上の2つの操作は除外されます:
{ "include": [ { "host": [ "v1.example.com", "v2.example.com" ] } ], "exclude": [ { "operation_ids": [ "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", // POST v1.example.com/login "56828eae-035a-4396-ba07-51c66d680a04" // POST v2.example.com/login ] } ]}操作はホストレベルで含めることができ、操作ごとに無視することができます。
このルールでカバーされる操作を確認するには、POST /zones/{zone_id}/api_gateway/token_validation/rules/previewエンドポイントを使用できます:
curl --request PUT \'https://api.cloudflare.com/client/v4/zones/{zone_id}/api_gateway/token_validation/rules/preview' \--header 'Content-Type: application/json' \--data '{ "include": [ { "host": [ "v1.example.com", "v2.example.com" ] } ], "exclude": [ { "operation_ids": [ "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", // POST v1.example.com/login "56828eae-035a-4396-ba07-51c66d680a04" // POST v2.example.com/login ] } ]}'レスポンスには、追加のstateフィールドを持つすべての操作が含まれます。
stateフィールドはignored、excluded、またはincludedのいずれかです。含まれる操作は、指定したホスト名セレクターに一致します。除外された操作は、セレクターで指定した操作IDに一致します。無視された操作は、セレクターで指定されたものに一致しない操作です。
{ "result": { "operations": [ { "operation_id": "ed15fcb6-5a73-41cd-91af-8c61e5bb1cdb", "method": "GET", "host": "example.com", "endpoint": "/api/accounts/{var1}", "last_updated": "2023-05-24T14:54:34.806506Z", "state": "ignored" }, { "operation_id": "e7a582cd-3cfb-4061-ab5b-722e6e42f545", "method": "GET", "host": "v1.example.com", "endpoint": "/api/accounts/{var1}", "last_updated": "2023-05-24T14:54:34.806506Z", "state": "included" }, { "operation_id": "ddd5df5a-795c-40ce-b38c-38e9d7ef9ae8", "method": "GET", "host": "v2.example.com", "endpoint": "/api/accounts/{var1}", "last_updated": "2023-05-24T14:54:34.806506Z", "state": "included" }, { "operation_id": "4d20befb-0120-45d5-9b29-5835fd41b44e", "method": "GET", "host": "v3.example.com", "endpoint": "/api/accounts/{var1}", "last_updated": "2023-05-24T14:54:34.806506Z", "state": "ignored" }, { "operation_id": "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", "method": "POST", "host": "v1.example.com", "endpoint": "/login", "last_updated": "2023-05-24T14:54:34.806506Z", "state": "excluded" }, { "operation_id": "56828eae-035a-4396-ba07-51c66d680a04", "method": "POST", "host": "v2.example.com", "endpoint": "/login", "last_updated": "2023-05-24T14:54:34.806506Z", "state": "excluded" }, { "operation_id": "cf86874c-8d0c-4337-ae14-4e2459b541ac", "method": "GET", "host": "v3.example.com", "endpoint": "login", "last_updated": "2023-05-24T14:54:34.806506Z", "state": "ignored" } ], "total": 7, "included": 2, "excluded": 2, "ignored": 3, "selected_hosts": [ "v1.example.com", "v2.example.com" ], "available_hosts": [ "example.com", "v1.example.com", "v1.example.com", "v3.example.com" ] }, "success": true, "errors": [], "messages": [], "result_info": { "page": 1, "per_page": 20, "count": 20, "total_count": 1631 }}included状態の操作は、トークン検証ルールの対象となります。レスポンスには、result.selected_hostsに含まれる操作のホスト名と、result.available_hostsにすべてのゾーン操作で使用されるホスト名が表示されます。
リクエストボディに空のオブジェクトを送信することもできます:
curl --request PUT \'https://api.cloudflare.com/client/v4/zones/{zone_id}/api_gateway/token_validation/rules/preview' \--header 'Content-Type: application/json' \--data '{ }'レスポンスには、すべてのゾーン操作とすべての可能なホストが表示され、独自のセレクターを構築するために使用できます。
以下の例は、Cloudflare APIを使用してトークン検証ルールを作成するために必要なすべての情報を含むJSONオブジェクトを示しています。
トークン設定IDや操作IDは、ゾーンに存在するIDに置き換えてください。
[ { "title": "v1およびv2.example.comでのJWT検証", "description": "有効な認証ヘッダーがないリクエストをログに記録します。", "action": "log", "enabled": true, "expression": "is_jwt_valid(\"00170473-ec24-410e-968a-9905cf0a7d03\")", "selector": { "include": [ { "host": [ "v1.example.com", "v2.example.com" ] } ], "exclude": [ { "operation_ids": [ "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", "56828eae-035a-4396-ba07-51c66d680a04" ] } ] } }]cURLまたは他のAPIクライアントツールを使用して、新しい構成をCloudflareのAPIに送信してJWT検証を有効にします。{zone_id}を関連するゾーンIDに置き換え、認証資格情報ヘッダーを追加してください。
トークン設定IDや操作IDは、ゾーンに存在するIDに置き換えてください。
1つのリクエストで複数のルールを作成できます。その場合、リクエストボディのJSON配列に複数のルールオブジェクトを渡します。
curl "https://api.cloudflare.com/client/v4/zones/{zone_id}/api_gateway/token_validation/rules" \--header 'Content-Type: application/json' \--data '[ { "title": "v1およびv2.example.comでのJWT検証", "description": "有効な認証ヘッダーがないリクエストをログに記録します。", "action": "log", "enabled": true, "expression": "is_jwt_valid(\"00170473-ec24-410e-968a-9905cf0a7d03\")", "selector": { "include": [ { "host": [ "v1.example.com", "v2.example.com" ] } ], "exclude": [ { "operation_ids": [ "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", "56828eae-035a-4396-ba07-51c66d680a04" ] } ] } }]'レスポンスはCloudflareのv4レスポンスエンベロープ内にあり、結果には作成されたルールが含まれます。各ルールの返されたIDに注意してください。これは、既存のルールを編集または削除するために使用できます。
{ "result": [ { "id": "5ec7c417-6964-4b24-b82c-a23a7ec8f90c", "title": "v1およびv2.example.comでのJWT検証", "description": "有効な認証ヘッダーがないリクエストをログに記録します。", "action": "log", "enabled": true, "expression": "is_jwt_valid(\"00170473-ec24-410e-968a-9905cf0a7d03\")", "selector": { "include": [ { "host": [ "v1.example.com", "v2.example.com" ] } ], "exclude": [ { "operation_ids": [ "f9c5615e-fe15-48ce-bec6-cfc1946f1bec", "56828eae-035a-4396-ba07-51c66d680a04" ] } ] }, "created_at": "2023-10-18T12:08:09.575388Z", "last_updated": "2023-10-18T12:08:09.575388Z", "modified_by": "user@cloudflare.com" } ], "success": true, "errors": [], "messages": []}一定の期間ごとにキーをローテーションすることがベストプラクティスです。キーを更新するために、Cloudflareは各設定に最大4つのキーを許可します。これにより、既存のキーに新しいキーを追加できます。新しいキーのみでJWTを発行し、一定の期間後に古いキーを削除することができます。さらに、この機能により、テストまたは開発用のキーを本番用のキーと並行して展開できます。
キーの更新に必要な入力は、初期キーを提供したときと同じで、資格情報キーを使用し、JWKである必要があります。
キーを更新するには、PUTコマンドを使用します。
curl --request PUT \'https://api.cloudflare.com/client/v4/zones/{zone_id}/api_gateway/token_validation/{config_id}/credentials' \--header 'Content-Type: application/json' \--data '{ "keys": [ { "kty": "EC", "use": "sig", "kid": "test", "x": "-0LNzBheJPn-Zy6JmanTIUX7xc3jgqU714IQY0oU6mw", "y": "KONxBybUcRsJQmtu17jMAHsILSw009AuU3ulfUGv3FI", "alg": "ES256" }, { "kty": "EC", "crv": "P-256", "kid": "test-2", "x": "iIbPRbOeLzjGPvv7iwmzCOTU03R0xDqbenp2D6GUcWo", "y": "tDkEh95PnfWwIXciCtdBBVA7wfghx_egmZ1Zcvu2lWw", "alg": "ES256" } ]}'{zone_id}を関連するゾーンIDに置き換え、認証情報ヘッダーを追加してください。
トークン検証ルールは、PATCHリクエストで更新できます。単一のPATCHリクエストで複数のルールを更新できます。
PATCHリクエストは、リクエストボディ内のJSON配列として指定されます。その配列内の各アイテムは、idによって定義された単一のルールへの更新を含みます。
以下の例は、1つのルールを更新し、別のルールを無効にします:
curl --request PATCH \"https://api.cloudflare.com/client/v4/zones/{zone_id}/api_gateway/token_validation/rules" \--header "Content-Type: application/json" \--data '[ { "id": "714d3dd0-cc59-4911-862f-8a27e22353cc", "action": "log", "title": "更新されたタイトル" }, { "id": "7124f9bc-d6b5-430d-b488-b6bc2892f2fb", "enabled": false }]'ルールは、PATCHボディ内に位置フィールドを設定することで順序を変更できます。
この例では、ルール714d3dd0-cc59-4911-862f-8a27e22353ccをルール7124f9bc-d6b5-430d-b488-b6bc2892f2fbの後に配置します:
curl --request PATCH \"https://api.cloudflare.com/client/v4/zones/{zone_id}/api_gateway/token_validation/rules" \--header 'Content-Type: application/json' \--data '[ { "id": "714d3dd0-cc59-4911-862f-8a27e22353cc", "position": { "after": "7124f9bc-d6b5-430d-b488-b6bc2892f2fb" } }]'この例では、ルール714d3dd0-cc59-4911-862f-8a27e22353ccをルール7124f9bc-d6b5-430d-b488-b6bc2892f2fbの前に配置します:
curl --request PATCH \"https://api.cloudflare.com/client/v4/zones/{zone_id}/api_gateway/token_validation/rules" \--header 'Content-Type: application/json' \--data '[ { "id": "714d3dd0-cc59-4911-862f-8a27e22353cc", "position": { "before": "7124f9bc-d6b5-430d-b488-b6bc2892f2fb" } }]'以下は、JWT検証が受信リクエストを処理する方法の概要です:
- 受信リクエストから構成に従ってJWTを抽出します。
- JWTをデコードし、JWTのヘッダーKIDクレームを探します。
- KIDとALGクレームを使用して、提供されたキーのリストから正しいキーを見つけます。
- 選択したキーを使用して署名を確認することで、JWTの真正性を検証します。
- JWTにEXPクレーム(有効期限)が含まれている場合、JWTが期限切れでないことを検証します。
- JWTにNBFクレーム(有効前時間)が含まれている場合、JWTがすでに有効であることを検証します。
- 最終的な検証結果とトークンが存在したかどうかは、ポリシーの設定されたアクション(
log/block)を適用するWAFに提供されます。