機械翻訳について

Webhookセキュリティとは

Webフックでは、HTTPプロトコルを使用してイベント情報をアダプタに送信するために、外部アプリケーションまたはサービスが必要です。

これらのメッセージを処理する前に、セキュリティ・ロジックを使用して、メッセージが有効なソースまたは送信者からのものであることを認証または検証する必要があります。

さらに、外部アプリケーションまたはサービスは、メッセージの交換中に検証情報を送信することがあります。 たとえば、メッセージにはイベント固有のキーが含まれる場合があり、このキーはイベントとともに送信されるキーと比較できます。 これにより、メッセージが正しいソースから送信されたかどうかを確認できます。

Webフックは、次の段階でセキュリティを実装できます:

ノート:

一部のシナリオでは、外部アプリケーションのAPIを呼び出すためにwebフック・トリガーが必要になる場合があるため、起動前に認証メカニズムが必要になります。 このシナリオを処理するには、アダプタ定義ドキュメントの接続セクションでコンポジット・セキュリティ・ポリシーを設計します。 インバウンド・メッセージ認証をサポートできるトリガー接続の構成方法の詳細は、「保護されたエンドポイントを起動するためのトリガー接続定義の作成」を参照してください。

Webフック登録時の検証

外部アプリケーションまたはサービスは、webフック登録プロセス中に検証を強制できます。

webフック登録プロセスの詳細は、「イベント・サブスクリプションの理解」を参照してください。

この登録プロセス中に、外部アプリケーションによって次の要件が強制される場合があります:

  • アダプタが受信するエンドポイントに送信されたpingに応答します。

    レスポンスは、単純な確認メッセージ、より具体的なレスポンス・メッセージまたはカスタム・レスポンス・メッセージのいずれかです。

  • 外部アプリケーションからのランタイム・メッセージの検証に関するセキュリティ情報を格納します。

  • メッセージをOracle Integrationに正常に送信するための認可または認証を取得できる情報を使用して、外部アプリケーションを初期化します。

Rapid Adapter Builderを使用して、これらのシナリオをすべてモデル化できます。

最も一般的な登録要件はpingリクエストです。 エンドポイントの登録が手動の場合、pingが確認される前に、イベントを処理する統合をアクティブ化する必要があります。 さらに、トリガーはpingリクエストの確認応答を返すvalidationRequestsロジックをモデル化する必要があります。

次の例に示すように、このロジックをモデル化できます。この場合、pingのソースを識別するために条件が適用されます。 このシナリオでは、リクエストにx-custom-eventのキーとpingの値を含むヘッダーがある場合、確認が発行されます。 レスポンスは、HTTPステータス・コード204で作成されます。 レスポンスは、イベント・プロデューサが必要とする任意のコンテンツです。

"validationRequests": [
  {
    "condition": "${.request.headers.\"x-custom-event\"==\"ping\"}",
    "response": {
      "status": 204
    }
  }
],

また、一部のシナリオでは、登録にpingまたは受信リクエストの処理が必要になる場合があります。 このようなシナリオでは、フローを使用して追加のロジックをモデル化できます。 メッセージが有効であることを確認するために、validationRequestsのオブジェクト・セットが実行されます。 条件が満たされない場合、受信メッセージは実行時に実行されません。

Webフック・メッセージの認証および検証

実行時にwebフック・メッセージの認証および検証メカニズムを実装できます。

アダプタ定義ドキュメントのconnectionセクションで、インバウンド・メッセージのランタイム・セキュリティ強制を「コンポジット」セキュリティ・ポリシーとして定義できます。 トリガー・セキュリティ・ポリシーでは、インバウンド・セクションとアウトバウンド・セクションの両方がサポートされています。

また、一部のシナリオでは、外部アプリケーションのAPIを呼び出すためにwebフック・トリガーが必要になるため、起動する認証メカニズムが必要になる場合があります。 次のようなシナリオがあります:

  • 外部アプリケーションからデータを読み取ってオプションを選択できるようにするトリガーの構成。

  • 外部アプリケーションからのメタデータ情報の読取りを必要とする動的スキーマの作成。

  • 外部アプリケーションのAPIをコールしてこれらのエンティティを作成する必要があるサブスクリプション登録および登録解除。

コンポジット・セキュリティ・ポリシーは、次の重要なプロパティで構成されます:

  • policyOutbound: 外部アプリケーションのAPIを呼び出すための認証スキームをモデル化します。 ほとんどのアプリケーションでは、標準のOAuthポリシーを使用してAPIを保護し、アウトバウンド・コールを許可します。

  • policyInbound: Oracle Integrationが外部アプリケーションによって送信されたランタイム・メッセージを認証または検証できるようにするセキュリティ・スキームをモデル化します。

ノート:

外部アプリケーションおよびサービスは、webフック・セキュリティの設計に大きく影響します。 ほとんどのサービスは、デジタル・シグネチャを使用してwebフック・メッセージを検証します。

policyInboundセクションは、デジタル・シグネチャをサポートしています。 有効な値は次のとおりです。

  • DIGITAL_SIGNATURE
  • HMAC_SIGNATURE_VALIDATION
  • RSA_SIGNATURE_VALIDATION
  • JWT_VALIDATION

GithubトリガーとHMAC_SIGNATURE_VALIDATION管理対象ポリシーを含むセキュリティ・ポリシー定義を示すサンプル・コードを次に示します:

"securityPolicies": [
   {
     "type": "composite",
     "description": "This policy is used by OIC for validating incoming requests as well as for invoking GitHub APIs",
     "displayName": "GitHub security policy",
     "scope": "TRIGGER",
     "policyOutbound": {
       "type": "managed",
       "policy": "OAUTH2.0_AUTHORIZATION_CODE_CREDENTIALS",
       "securityProperties": [
         {
           "name": "oauth.client.id",
           "displayName": "Client Id",
           "description": "Client Id",
           "shortDescription": "Client Id",
           "required": true,
           "hidden": false
         },
         {
           "name": "oauth.client.secret",
           "displayName": "Client Secret",
           "description": "Client Secret",
           "shortDescription": "Client Secret",
           "required": true,
           "hidden": false
         },
         {
           "name": "oauth.access.token.uri",
           "default": "https://github.com/login/oauth/access_token",
           "required": false,
           "hidden": true
         },
         {
           "name": "oauth.scope",
           "displayName": "Scope",
           "description": "The scope of the access request",
           "shortDescription": "scope",
           "required": false,
           "hidden": false
         },
         {
           "name": "oauth.auth.code.uri",
           "default": "https://github.com/login/oauth/authorize",
           "required": false,
           "hidden": true
         },
         {
           "name": "authRequest",
           "default": "${(.securityProperties.\"oauth.auth.code.uri\") + \"?response_type=code&client_id=\" + (.securityProperties.\"oauth.client.id\") + \"&redirect_uri=${redirect_uri}&scope=\" + (.securityProperties.\"oauth.scope\")}",
           "required": true,
           "hidden": true
         },
         {
           "name": "accessTokenRequest",
           "description": "Access Token Request that should be used to fetch the access token",
           "shortDescription": "Example: -X <Method> -H <headers> -d <string-data> <access-token-uri>?<query params>",
           "default": "${\"-X POST -H \" + \"\\\"Accept: application/json\\\" -H \\\"Content-Type: application/x-www-form-urlencoded\\\" -d \\\"false\\\" \\\"\" +  (.securityProperties.\"oauth.access.token.uri\") + \"?code=${auth_code}&client_id=\" + (.securityProperties.\"oauth.client.id\") + \"&redirect_uri=${redirect_uri}&client_secret=\" + (.securityProperties.\"oauth.client.secret\") + \"&grant_type=authorization_code\\\"\"}",
           "required": true,
           "hidden": true
         },
         {
           "name": "refreshTokenRequest",
           "description": "Refresh Token Request that should be used to fetch the access token",
           "shortDescription": "Example: -X <Method> -H <headers> -d <string-data> <refresh-token-uri>?<query params>",
           "required": true,
           "default": "${\"-X POST -H \" + \"\\\"Accept: application/json\\\" -H \\\"Content-Type: application/x-www-form-urlencoded\\\" -d \\\"false\\\" \\\"\" +  (.securityProperties.\"oauth.access.token.uri\") + \"?refresh_token=${refresh_token}&client_id=\" + (.securityProperties.\"oauth.client.id\") + \"&redirect_uri=${redirect_uri}&client_secret=\" + (.securityProperties.\"oauth.client.secret\") + \"&grant_type=refresh_token\\\"\"}",
           "hidden": true
         },
         {
           "name": "$auth_code",
           "description": "Regex that identifies the auth code",
           "shortDescription": "Auth Code Regex",
           "required": false,
           "default": "${auth_code}",
           "hidden": true
         },
         {
           "name": "$access_token",
           "description": "Regex that identifies the access token",
           "shortDescription": "Access Token Regex",
           "required": false,
           "default": "access.[tT]oken",
           "hidden": true
         },
         {
           "name": "$refresh_token",
           "description": "Regex that identifies the refresh token",
           "shortDescription": "Default: refresh.[tT]oken",
           "required": false,
           "default": "refresh.[tT]oken",
           "hidden": true
         },
         {
           "name": "$expiry",
           "description": "Numeric value (in seconds)that specifies the expiry interval or a regex that identifies when the access token expires.",
           "shortDescription": "Default: expires_in",
           "required": false,
           "default": "expires.*",
           "hidden": true
         },
         {
           "name": "$token_type",
           "description": "Regex that identifies the access token type.",
           "shortDescription": "Default: token.?[tT]ype",
           "required": false,
           "default": "token.?[tT]ype",
           "hidden": true
         },
         {
           "name": "accessTokenUsage",
           "description": "Access token usage. A curl type syntax to illustrate how access token should be passed to access a protected resource.",
           "shortDescription": "Default: -H Authorization ${token_type} ${access_token}",
           "required": false,
           "default": "-H Authorization: Bearer ${access_token}",
           "hidden": true
         }
       ]
     },
     "policyInbound": {
       "type": "managed",
       "policy": "HMAC_SIGNATURE_VALIDATION",
       "securityProperties": [
         {
           "name": "signature",
           "hidden": true,
           "required": true,
           "default": "${connectivity::hexDecode(.request.headers.\"x-hub-signature-256\" | split(\"sha256=\")[1])}"
         },
         {
           "name": "signatureString",
           "displayName": "Request Signature Location",
           "hidden": true,
           "required": true,
           "default": "${.request.body}"
         },
         {
           "name": "signatureAlgorithm",
           "displayName": "Request Signature Algorithm",
           "hidden": true,
           "required": true,
           "default": "HMACSHA256"
         },
         {
           "name": "secret",
           "displayName": "Shared Secret",
           "hidden": false,
           "required": true
         },
         {
           "name": "timestampValidator",
           "displayName": "Timestamp Validation",
           "hidden": true,
           "required": false,
           "default": ""
         }
       ]
     }
   }

JWT_VALIDATIONセキュリティ・ポリシーのモデリングを示すサンプル・コードを次に示します。このコードは、Google Cloud Publication Subscriptionでメッセージ検証用に規定されています。

"securityPolicies": [
  {
    "type": "managed",
    "policy": "OAUTH_AUTHORIZATION_CODE_CREDENTIALS",
    "description": "This policy is used by OIC for invoking GCP Pub/Sub APIs",
    "displayName": "Google Authentication/Authorization Policy",
    "scope": "ACTION",
    "securityProperties": [
      {
        "name": "oauth.client.id",
        "displayName": "Google Client ID",
        "description": "Google Client ID",
        "shortDescription": "Example: 6-jdek24mqqhdleori19r.apps.googleusercontent.com",
        "required": true,
        "hidden": false
      },
      {
        "name": "oauth.client.secret",
        "displayName": "Google Client Secret",
        "description": "Google Client Secret",
        "shortDescription": "Example: GOCDPX-gBQdjksUPXWer4",
        "required": true,
        "hidden": false
      },
      {
        "name": "oauth.access.token.uri",
        "default": "https://oauth2.googleapis.com/token",
        "required": false,
        "hidden": true
      },
      {
        "name": "oauth.scope",
        "default": "https://www.googleapis.com/auth/pubsub",
        "required": false,
        "hidden": true
      },
      {
        "name": "oauth.auth.code.uri",
        "default": "https://accounts.google.com/o/oauth2/auth",
        "required": false,
        "hidden": true
      },
      {
        "name": "clientAuthentication",
        "default": "client_credentials_in_body",
        "required": false,
        "hidden": true
      }
    ],
    "authflow": "flow:extended-oauth"
  },
  {
    "type": "composite",
    "description": "This policy is used by OIC for validating incoming requests as well as for invoking GCP Pub/Sub APIs",
    "displayName": "GCP Pub/Sub security policy",
    "scope": "TRIGGER",
    "policyOutbound": {
      "type": "managed",
      "policy": "OAUTH_AUTHORIZATION_CODE_CREDENTIALS",
      "securityProperties": [
        {
          "name": "oauth.client.id",
          "displayName": "Google Client ID",
          "description": "Google Client ID",
          "shortDescription": "Example: 35532456156-jdek24mdmlqutog3gnc3rfqqhdleori19r.apps.googleusercontent.com",
          "required": true,
          "hidden": false
        },
        {
          "name": "oauth.client.secret",
          "displayName": "Google Client Secret",
          "description": "Google Client Secret",
          "shortDescription": "Example: GOCDPX-gBQdjnPG4Hdi940zJCuksUPXWer4",
          "required": true,
          "hidden": false
        },
        {
          "name": "oauth.access.token.uri",
          "default": "https://oauth2.googleapis.com/token",
          "required": false,
          "hidden": true
        },
        {
          "name": "oauth.scope",
          "default": "https://www.googleapis.com/auth/pubsub",
          "required": false,
          "hidden": true
        },
        {
          "name": "oauth.auth.code.uri",
          "default": "https://accounts.google.com/o/oauth2/auth",
          "required": false,
          "hidden": true
        },
        {
          "name": "clientAuthentication",
          "default": "client_credentials_in_body",
          "required": false,
          "hidden": true
        }
      ]
    },
    "policyInbound": {
        "type": "managed",
        "policy": "JWT_VALIDATION",
        "securityProperties": [
            {
                "name": "subjectClaim",
                "displayName": "Subject claim Override",
                "hidden": true,
                "required": false,
                "default": ""
            },
            {
                "name": "jwtToken",
                "displayName": "JWT Token",
                "hidden": true,
                "required": true,
                "default": "${.request.headers.authorization|split(\" \")|.[1]}"
            },
            {
                "name": "signatureKey",
                "displayName": "JWK URL",
                "hidden": true,
                "required": true,
                "default": "https://www.googleapis.com/oauth2/v3/certs"
            },
            {
                "name": "customClaimsValidation",
                "displayName": "Custom Claims Validation",
                "hidden": true,
                "required": false,
                "default": ""
            }
        ]
    }

次に、policyInboundセクションがOAuth管理ポリシーOAUTH_INBOUNDを使用するセキュリティ・ポリシーを示すサンプル・コードを示します。 webフック・メッセージは、すべてのアプリケーションがOracle IntegrationのAPIを呼び出す方法と同様に、Oracle Integrationで認証されます。

ただし、このポリシーでは、外部アプリケーションを適切な資格証明で初期化するために手動設定が必要であり、外部アプリケーションは適切な認証アーティファクトを取得する必要があります。

webフック・メッセージのヘッダーにあるベアラー・トークンを使用すると、Oracle Integrationでインバウンド・メッセージを認証できます。

{
    "type": "composite",
    "description": "This policy is used by Oracle Integration to validate incoming requests for Zuora APIs",
    "displayName": "Zuora Composite Security Policy",
    "scope": "TRIGGER",
    "policyOutbound": {
        "type": "managed",
        "policy": "OAUTH2.0_CLIENT_CREDENTIALS",
        "securityProperties": [
            {
                "name": "oauth.client.id",
                "displayName": "Client Id",
                "description": "Used to identify the client(the software requesting an access token) that is making the request. The value passed in this parameter must exactly match the value shown in your API console project.",
                "shortDescription": "Used to identify the client.",
                "required": true,
                "hidden": false
            },
            {
                "name": "oauth.client.secret",
                "displayName": "Client Secret",
                "description": "Used to authorize the client(the software requesting an access token) that is making the request.  The value passed in this parameter must exactly match the value shown in your API console project.",
                "shortDescription": "<unique random string matches your API console project>",
                "required": true,
                "hidden": false
            },
            {
                "name": "oauth.access.token.uri",
                "description": "A request should be sent to this URI for obtaining an access token.",
                "default": "${\"https:/\"+\"/\"+.connectionProperties.invokeHostName + \"/oauth/token\"}",
                "required": true,
                "hidden": true
            },
            {
                "name": "oauth.scope",
                "description": "Permissions your application is requesting on behalf of the user.",
                "shortDescription": "For example: read,write.",
                "default": "",
                "required": false,
                "hidden": true
            },
            {
                "name": "accessTokenRequest",
                "description": "Access Token Request that should be used to fetch the access token",
                "shortDescription": "Example: -X <Method> -H <headers> -d <string-data> <access-token-uri>?<query params>",
                "default": "${\"-X POST -H \" + \"\\\"Content-Type: application/x-www-form-urlencoded\\\" -d \\\"client_id=\" + (.securityProperties.\"oauth.client.id\") + \"&client_secret=\" + ((.securityProperties.\"oauth.client.secret\"|=@uri).securityProperties.\"oauth.client.secret\") + \"&grant_type=client_credentials\\\" \" + \"\\\"https://\" + .connectionProperties.invokeHostName + \"/oauth/token\\\"\"}",
                "required": true,
                "hidden": true
            },
            {
                "name": "refreshTokenRequest",
                "description": "Refresh Token Request that should be used to fetch the access token",
                "shortDescription": "Example: -X <Method> -H <headers> -d <string-data> <refresh-token-uri>?<query params>",
                "required": false,
                "default": "",
                "hidden": true
            },
            {
                "name": "$access_token",
                "description": "Regex that identifies the access token",
                "shortDescription": "Access Token Regex",
                "required": false,
                "default": "access.[tT]oken",
                "hidden": true
            },
            {
                "name": "$refresh_token",
                "description": "Regex that identifies the refresh token",
                "shortDescription": "Default: refresh.[tT]oken",
                "required": false,
                "default": "refresh.[tT]oken",
                "hidden": true
            },
            {
                "name": "$expiry",
                "description": "Numeric value (in seconds)that specifies the expiry interval or a regex that identifies when the access token expires.",
                "shortDescription": "Default: expires_in",
                "required": false,
                "default": "expires.*",
                "hidden": true
            },
            {
                "name": "$token_type",
                "description": "Regex that identifies the access token type.",
                "shortDescription": "Default: token.?[tT]ype",
                "required": false,
                "default": "token.?[tT]ype",
                "hidden": true
            },
            {
                "name": "accessTokenUsage",
                "description": "Access token usage. A curl type syntax to illustrate how access token should be passed to access a protected resource.",
                "shortDescription": "Default: -H Authorization ${token_type} ${access_token}",
                "required": false,
                "default": "-H Authorization: Bearer ${access_token}",
                "hidden": true
            }
        ]
    },
    "policyInbound": {
        "type": "managed",
        "policy": "OAUTH_INBOUND"
    }
}