ガイドと洞察

パートナー API Authorization AI のテスト API 販売代理店ポータル

顧客の作成、キーの発行、クレジットの追加、使用量のエクスポート、アクセスの凍結を行うパートナー API でのクロステナント アクセスを防止するための実践的なテスト計画。

再販業者ポータルのパートナー API は、リクエスト内のすべてのオブジェクト ID がコピー、推測、再生、別の統合によって記録される、または間違ったスタッフ ツールを経由する可能性があることを想定する必要があります。中心的な問題は、顧客 ID が不透明かどうかではありません。問題は、すべてのアクションが、呼び出し元、パートナー アカウント、ターゲット テナント、オブジェクト、プロパティ、および承認状態が一緒に属していることを証明するかどうかです。

これは、AI API リセラー ポータル で最も重要です。API は、通常、ダウンストリーム顧客、仮想 API キー、ウォレット、クレジット調整、使用量エクスポート、Webhook 宛先、スタッフ ユーザー、緊急フリーズなど、影響の大きいコントロール プレーン オブジェクトを公開するためです。承認チェックが 1 つ欠けていると、ある顧客が別の顧客の使用状況を読み取ることができたり、スタッフ トークンがテナント間でクレジットを移動したり、自動トークンが決して参照する必要のないキーを取り消したりする可能性があります。

事実: OWASP API セキュリティ 2023 では、壊れたオブジェクト レベル Authorization が API1 として、壊れたオブジェクト プロパティ レベル Authorization が API3 としてリストされています。実際には、オブジェクト レベルのチェックは、「この呼び出し元はこのオブジェクトに対して動作できるか?」という質問に答えます。一方、プロパティレベルのチェックでは、「この呼び出し元はこのフィールドを設定または読み取ることができますか?」という質問に答えます。どちらもパートナー API の設計にとって第一級の懸念事項です。

テストを作成する前に Authorization 契約を定義する

Authorization テストは、明示的なポリシー契約に対してテストする場合にのみ役立ちます。どのアクターがどのターゲットに対してどの条件下でどのアクションを実行できるかを説明するマトリックスから始めます。ポリシーとしてエンドポイント名や UI ロールに依存しないでください。

有用な行列には次の列があります:

  • アクター タイプ: パートナー オーナー、パートナー管理者、財務オペレーター、サポート オペレーター、自動化トークン、顧客管理者、顧客読み取り専用ユーザー。
  • パートナー アカウント: 下流の顧客関係を所有する再販業者または代理店のアカウント。
  • ターゲット テナント: 作成、請求、検査、一時停止、または削除されるダウンストリーム顧客アカウント。
  • オブジェクト タイプ: 顧客、仮想キー、ウォレット、台帳エントリ、使用状況レポート、Webhook エンドポイント、スタッフ ユーザー、価格設定プロファイル、プロバイダー マッピング。
  • アクション: 作成、読み取り、リスト、更新、取り消し、補充、払い戻し、エクスポート、凍結、凍結解除。
  • 通貨当局: アクションによって残高、与信限度額、証拠金、決済ステータス、請求書の状態、または支出上限が変更されるかどうか。
  • 承認状態: リクエストが事前承認、承認待ち、二重承認、期限切れ、または緊急のみのいずれであるか。

たとえば、サポート オペレーターは、顧客のマスクされたキーのメタデータを表示したり、インシデント中にキーを凍結したりすることは許可されますが、承認なしにクレジットの作成、価格カタログの変更、完全な使用状況データのエクスポート、またはキーの凍結解除は許可されない場合があります。金融オペレータは、同じパートナーが所有する顧客に対して信用調整を作成する場合がありますが、これは構成された金額内でのみ、かつ承認レコードが存在した後にのみ行われます。

推奨事項: マトリックスをバージョン管理されたアーティファクトとして書き込み、すべての認可テスト名が行またはルールを参照するようにします。ポリシーが変更されると、差分には契約の変更とテストの変更の両方が表示される必要があります。

テナントにバインドされたオブジェクト参照を使用する

不透明な ID は列挙のリスクを軽減しますが、承認を証明するものではありません。仮想キー ID、ウォレット ID、台帳エントリ ID、使用状況エクスポート ID、またはカーソル トークンは、予想されるパートナーとテナントの境界内で解決される必要があります。

安全な検索パターンは次のとおりです:

resolve object where
  object.id = request.object_id
  and object.partner_id = actor.partner_id
  and object.customer_id = request.customer_id
  and actor has action_scope for object_type/action
  and object.state allows action

危険なパターンは次のとおりです:

object = find_by_id(request.object_id)
if actor.has_scope("keys:revoke"):
  revoke(object)

2 番目のバージョンは、ターゲットに対する権限ではなく、スコープの所有を承認します。パートナー A の有効なトークンがパートナー B からキー ID を送信する場合、または顧客 A のオペレーターが顧客 B からウォレット ID を送信する場合は失敗します。

テナント バインディングは、明らかなオブジェクト以上のものをカバーする必要があります。使用状況レポートのカーソル トークン、エクスポート ジョブ ID、Webhook エンドポイント ID、承認 ID、べき等キー、レジャー調整 ID を含めます。これらのオブジェクトは多くの場合「内部」であると感じられ、まさにそれが弱点となる理由です。

最小限のクロステナント テスト フィクスチャを構築する

誤ったアクセスを表現しやすくするために、意図的に小さいフィクスチャを使用します。目標は大量のデータではありません。目標は明確な分離です。

Partner P1
  Staff: p1_owner, p1_support, p1_finance
  Token: p1_full_token, p1_support_token, p1_finance_token
  Customer C1A
    Key K1A
    Wallet W1A
    Usage cursor U1A
    Ledger entry L1A
  Customer C1B
    Key K1B
    Wallet W1B
    Usage cursor U1B
    Ledger entry L1B

Partner P2
  Staff: p2_owner
  Token: p2_full_token
  Customer C2A
    Key K2A
    Wallet W2A
    Usage cursor U2A
    Ledger entry L2A

このフィクスチャを使用すると、2 つの障害クラスをテストできます。 1 つ目は、同一パートナー間の顧客間アクセスです。P1 からの発信者が C1A 上で動作している間に C1B にタッチしようとします。 2 番目は、クロスパートナー アクセスです。P1 トークンが P2 のオブジェクトにアクセスしようとします。

推奨事項: パブリック パートナー API と販売代理店ポータル バックエンドに対して同じフィクスチャを実行します。 UI 制限では、直接 API クライアント、バックグラウンド ジョブ、ブラウザ開発ツール、または侵害された統合トークンは保護されません。

影響の大きいすべてのエンドポイントでオブジェクト レベル Authorization をテスト

オブジェクト ID を受け入れるエンドポイントごとに、少なくとも 1 つの肯定的なテストといくつかの否定的なテストを作成します。テストが肯定的であれば、フィクスチャが有効であることが証明されます。陰性テストは境界が保持されることを証明します。

顧客の作成と検索

ターゲット テナントがまだ存在しないため、顧客の作成は通常は無害に見えます。呼び出し元が別のパートナーの下で顧客を作成したり、禁止された価格設定プロファイルを割り当てたり、内部メタデータを設定しようとしたりする可能性があるため、依然として承認が必要です。

テストケース:

  • パートナー所有者は、同じパートナーの下に顧客を作成できます。
  • 顧客プロビジョニング スコープを持つ自動化トークンは、同じパートナーの下に顧客を作成できます。
  • サポート専用トークンでは顧客を作成できません。
  • P1 トークンは partner_id=P2 の顧客を作成できません。
  • 顧客レベルのトークンでは兄弟顧客をリストすることはできません。

キーの作成、取り消し、およびローテーション

主要なライフサイクル アクションは、ランタイム アクセスを許可し、本番環境のワークロードを中断する可能性があるため、影響が大きくなります。プロバイダーのコントロール プレーンは通常、プロジェクト、ワークスペース、サービス アカウント、メンバー、API キーなどの管理オブジェクトを API 経由で公開します。ゲートウェイまたはリセラー層は、独自の仮想キーを同様に注意して扱う必要があります。

テストケース:

  • P1 オートメーションは、トークンにキー書き込みスコープが含まれている場合、C1A に対してのみ K1A を作成できます。
  • サポートの役割がキーの読み取り専用である場合、P1 サポートは K1A を作成できません。
  • P1 サポートは、緊急凍結が範囲内にある場合にのみ K1A を凍結できます。
  • リクエスト コンテキストが C1A である場合、P1 サポートは K1B を取り消すことができません。
  • P1 完全トークンは K2A を取り消すことができません。
  • C1A の顧客管理者は、K1B をローテーション、公開、または取り消すことはできません。

パートナー API 自動化を実装しているチームにとって、重要なテストは単に「このトークンにキー書き込み機能があるか?」ということではありません。それは、「このトークンには、このパートナー、この顧客、このキー、この状態、およびこの操作に対するキー書き込みがありますか?」

クレジットのチャージとウォレットの変更

お金を動かすアクションには、通常のアップデートよりも厳格なテストが必要です。ウォレットが別のテナントに属している、金額が権限を超えている、承認レコードが別の顧客を対象としている、冪等キーが最初に別の操作に使用されているなどの理由により、クレジット チャージは構文的には正しくても未承認である可能性があります。

テストケース:

  • P1 ファイナンスは、承認後に金額制限内で W1A を補充できます。
  • P1 ファイナンスでは、W1A 用に作成された承認を使用して W1B を補充することはできません。
  • P1 金融は W2A を補充できません。
  • P1 サポートではウォレットにチャージできません。
  • 自動化トークンは、明示的な資金移動範囲を持たない限り、信用限度額を変更できません。
  • 再実行された冪等キーは、以前の W1A チャージを W1B にリダイレクトできません。

推奨事項: 冪等キーは、パートナー、操作、ターゲット テナント、正規化されたリクエスト本文をスコープとするものとして扱います。再試行は安全である必要がありますが、テナント間の衝突チャネルになってはなりません。

使用状況レポートとエクスポート カーソル

使用状況レポートは読み取り専用であるため、保護が不十分になりやすいです。再販業者システムでは、使用状況データにより、顧客名、ワークロード、モデルの選択、コスト、エンドユーザー識別子、および商業マージンが明らかになる可能性があります。 Cursor トークンとエクスポート ID もテナントにバインドする必要があります。

テストケース:

  • C1A 管理者は C1A 使用状況バケットを読み取ることができます。
  • C1A 管理者は、customer_id を変更しても C1B の使用状況を読み取ることができません。
  • P1 読み取り専用分析トークンは、エクスポート スコープが存在する場合にのみ、P1 顧客の使用状況をエクスポートできます。
  • P1 トークンは、コピーされたカーソルを使用して P2 使用量のエクスポートを再開できません。
  • 明示的に許可されていない限り、キーレベルのレポート用に作成されたカーソルを再利用してテナント全体の使用状況を取得することはできません。

ポータルが AI API 顧客使用状況測定 を公開している場合は、概要ビューとダウンロード可能なエクスポートの両方をテストします。エクスポート パスは、多くの場合、インタラクティブ ページで使用される同じコントローラまたはポリシー コードをバイパスします。

PATCH および更新エンドポイントでプロパティ レベル Authorization をテスト

壊れたオブジェクト プロパティ レベル Authorization は、呼び出し元がオブジェクトの更新を許可されているが、内部フィールド、特権フィールド、または別のワークフローによって所有される必要があるフィールドを設定できる場合に表示されます。

パートナー API の場合、機密フィールドには次のものが含まれることがよくあります:

  • partner_id、customer_id、および親所有権フィールド。
  • provider_project_id、provider_workspace_id、および上流のキー参照。
  • pricing_catalog_version、margin_tier、および割引の上書き。
  • wallet_balance、credit_limit、settlement_status、請求書の状態
  • fraud_status、risk_score、およびコンプライアンス フラグ。
  • role、scopes、および承認バイパス フラグ。

拒否リストではなく許可リストを使用します。たとえば、顧客プロファイル更新エンドポイントでは display_name、billing_email、metadata.external_reference が許可される場合があります。呼び出し元が顧客オブジェクトを更新できる場合でも、margin_tier、credit_limit、provider_project_id は拒否または無視される必要があります。

PATCH /partner/customers/C1A
{
  "display_name": "Acme Support Team",
  "margin_tier": "internal_zero_margin",
  "provider_project_id": "provider-project-owned-by-C1B"
}

期待される結果は決定的である必要があります。機密の内部値を明らかにせずに、許可されていないフィールドを識別する検証エラーを優先します。 API コントラクトがすでにそのパターンを一貫して使用している場合を除き、特権フィールドを黙って受け入れて無視しないでください。

拒否を列挙しないようにする

ネガティブ テストでは、ステータス コードと応答形状の両方をチェックする必要があります。 P1 トークンが K2A を要求した場合、その応答で K2A が別のパートナーの下に存在するかどうかが明らかにならないようにする必要があります。

一般的なルールは次のとおりです:

  • 呼び出し元が認証されていない場合は 401 を使用します。
  • 呼び出し元が認証されているが、独自の境界内にアクション スコープがない場合は、403 を使用します。
  • オブジェクトが呼び出し元の境界外にあり、存在を明らかにすべきでない場合は、404 または一般的な not-found 応答を使用します。

正確な規則は異なる場合がありますが、動作は一貫している必要があります。拒否本文では、「キーは別の顧客のものです」または「ウォレットはパートナー P2 の下に存在します」などのメッセージを避ける必要があります。その情報は攻撃者にとっては有益ですが、正規のクライアントにとってはほとんど役に立ちません。

トレードオフ: 一般的な拒否により、パートナー デベロッパーのデバッグが困難になります。この問題は、パブリック API エラーでクロステナントの存在を漏らすのではなく、リクエスト ID、構造化された監査ログ、サポート ツールを使用して解決します。

機密ペイロードではなく、Authorization 決定を記録します

Authorization テストでは、否定によって有用な内部証拠が生成されることも主張する必要があります。生のプロンプト、秘密、または不要な顧客データを保存せずに、インシデント中に何が起こったかを再構築するには、十分な詳細が必要です。

ログフィールドには以下を含める必要があります:

  • request_id およびトレース相関 ID.
  • actor_id、アクター タイプ、トークン ID、およびロール テンプレート。
  • 認証されたアクターからの
  • partner_id。
  • 解決が許可されている場合、要求されたターゲット テナントと解決されたターゲット テナント。
  • オブジェクトのタイプとアクション。
  • ポリシーのバージョンと決定結果。
  • 拒否理由コード (missing_scope、tenant_mismatch、approval_required、field_not_allowed など)。

完全な API キー、上流プロバイダーのシークレット、プロンプト、生の使用状況ペイロード、または完全なエクスポート コンテンツをログに記録しないでください。拒否されたテナント間リクエストの場合は、内部ログがアクセス制御されていることに注意してください。セキュリティチームがまだ十分な証拠を持っている間は、世間の反応は一般的なものになる可能性があります。

CI とステージングでハーネスを自動化する

テスト ハーネスは、ポリシー機能の単体テスト、API エンドポイントの統合テスト、デプロイされた販売代理店ポータル バックエンドに対するステージング プローブの 3 つの場所で実行する必要があります。各層は異なる障害を検出します。

実用的な CI 構造:

authz-tests/
  fixtures/
    partners.json
    customers.json
    roles.json
    tokens.json
  matrix/
    keys.yaml
    wallets.yaml
    usage_exports.yaml
    customers.yaml
  tests/
    test_keys_authz.ts
    test_wallet_authz.ts
    test_usage_authz.ts
    test_patch_allowlists.ts

行列の各行は、アクター、リクエスト、期待される決定、および期待される非列挙動作を定義する必要があります。

- name: p1_support_cannot_revoke_p2_key
  actor: p1_support_token
  method: POST
  path: /partner/customers/C2A/keys/K2A/revoke
  expected_status: 404
  expected_error_code: not_found
  expected_audit_reason: tenant_mismatch

一度に 1 つの識別子 (顧客 ID、キー ID、ウォレット ID、承認 ID、カーソル、べき等キー、Webhook エンドポイント ID) を交換するミューテーション スタイルのバリアントを追加します。これらのテストは設計により繰り返し行われます。すべての識別子のスコープが独立していることが証明される場合、繰り返しは許容されます。

運用チェックリスト

パートナー API エンドポイントを出荷する前に、次のチェックリストを使用してください:

  • エンドポイントには、ポリシー マトリックスに名前付き認可ルールがあります。
  • すべてのオブジェクト検索には、パートナーとテナントの境界条件が含まれます。
  • すべてのリストのエンドポイントは、ページネーションの前にアクター境界によってフィルター処理されます。
  • すべてのカーソル、エクスポート ID、Webhook ID、承認 ID、冪等キーはスコープされます。
  • PATCH エンドポイントは、ロールとアクションごとにプロパティ許可リストを使用します。
  • お金を動かすアクションには、明示的な範囲と承認状態が必要です。
  • 緊急凍結は、凍結解除および信用機関から分離されています。
  • 拒否により、テナント間の存在漏洩が回避されます。
  • 監査ログには、認可の決定とポリシーのバージョンが記録されます。
  • 同じネガティブ テストが API およびポータル バックエンド パスに対して実行されます。

明示的に決定するトレードオフ

きめ細かいスコープにより爆発範囲は縮小しますが、パートナーのオンボーディングは複雑になります。デフォルトのロール テンプレートは、所有者、財務、サポート、分析、プロビジョニングの自動化、および緊急対応に役立ちます。上級パートナーは、生のスコープから始めるのではなく、これらのテンプレートからカスタマイズできるようにします。

新しい編集可能なフィールドごとにポリシーの変更が必要になるため、厳格なプロパティ許可リストでは機能の展開が遅くなります。この摩擦は、請求、価格設定、プロバイダー マッピング、キー管理の分野に役立ちます。リスクの低いプロファイルのフィールドの場合、プロセスはより軽量になる可能性があります。

承認フローにより、偶発的または悪意のあるクレジット変更が削減されますが、正規のサポート操作に待ち時間が追加されます。緊急凍結は迅速かつ可逆的であり、個別に範囲が設定されています。同じ緊急トークンでクレジットの追加、マージンの変更、使用量のエクスポート、アカウントの凍結解除を行わないでください。

予測: 顧客はセルフサービスのプロビジョニング、レポート、自動化を期待しているため、再販業者ポータルはパートナー API を通じてさらに多くの管理アクションを公開し続けるでしょう。十分に古くなったシステムとは、ルートの名前付け、非表示の UI コントロール、または不透明な ID のみに依存するシステムではなく、認可コントラクトとネガティブ テストを備えたシステムです。

実用的な結論

パートナー API が十分に大きくなり、すべてのエンドポイントに独自の例外が発生する前に、認可ハーネスを構築します。 2 人のパートナー、1 つのパートナーの下に 2 人の顧客、別のパートナーの下に 1 人の顧客、および少数のトークンのセットから始めます。次に、キーの作成、キーの失効、クレジットの追加、使用状況のエクスポート、ウォレットの更新、承認の再利用、冪等性のリプレイ、PATCH フィールドなど、最も害を及ぼす可能性のあるアクションをテストします。

契約の内容は簡単です。呼び出し元は、適切なパートナーの下で、適切なテナント、オブジェクト、プロパティ、アクション、金額、承認状態について適切なスコープを持っている必要があります。実装作業により、退屈なエンドポイントを含むすべてのエンドポイントでこれが実現されます。

関連資料

FAQ

よくある質問

不透明な ID はテナント間のパートナー API アクセスを防ぐのに十分ですか?
いいえ、不透明な ID により推測と列挙のリスクは軽減されますが、すべてのリクエストには依然としてアクター、パートナー、テナント、オブジェクト、アクション、状態をバインドする承認チェックが必要です。
認可テストはパブリック API に対してのみ実行する必要がありますか?
いいえ。パブリック パートナー API および再販業者ポータル バックエンドに対して実行します。 UI チェックでは、直接 API クライアント、バックグラウンド ワーカー、侵害されたトークン、または代替バックエンド ルートは保護されません。
最初に否定的な承認テストが必要なパートナー API エンドポイントはどれですか?
影響力の大きいエンドポイントから始めます: 顧客の作成、キーの作成と取り消し、ウォレットのチャージ、クレジット制限、使用量のエクスポート、承認レコード、べき等キー、Webhook の送信先、顧客または請求オブジェクトの PATCH エンドポイント。
トークンが別のテナントのオブジェクトを参照する場合、API はどのように応答すべきでしょうか?
非列挙応答規則を使用します。多くの API は、オブジェクトが呼び出し元の境界外にある場合、一般的な not found 応答を返しますが、正確な拒否理由は内部監査ログに記録されます。