メインコンテンツにスキップ

検証

場合によっては、インテグレーションで受信するフックが、Pio以外からのものや攻撃などではないかを確認する必要があるかもしれません。PioからRESTフックが送信される際、ヘッダーにはペイロードとともに署名やその他の情報が含まれます。これにより、受信側で署名を計算し、照合や検証ができるようになっています。

また、PioシステムによるWebhookの送信時には、User-Agent: Pio-Webhooks/1.0がヘッダーとして与えられます。

ヘッダーに含まれる情報は次のとおりです。

バージョン1のWebhook

含まれるヘッダーは次のとおりです。

  • X-Pio-Hmac-Sha256:HMAC-SHA256署名です。
  • X-Pio-Delivery-Id:WebhookのIDです。冪等性を確保するために使用されます。
  • X-Pio-Event-Type:Webhookが参照するイベントの種類です。イベントの種類については、以下の関連セクションで説明します。
  • X-Pio-Shop-Id:Webhookの対象となるショップのPio IDです。
  • X-Pio-Ext-Shop-Id:Webhookの対象となるショップのインテグレーション提供IDです。
  • X-Pio-Timestamp:リクエストが行われた時刻を表す、Unixタイムスタンプです。

PioのWebhookを検証するPythonコードの例は次のとおりです。

import hashlib
import hmac
import base64
import secrets

# your integration's `client_secret`
client_secret: str = <...>
# get the payload from the request
payload: bytes = <...>
payload_str = payload.decode('utf-8')
data_to_sign = f"{x_pio_event_type}:{x_pio_delivery_id}:{x_pio_timestamp}:{x_pio_shop_id}:{x_pio_ext_shop_id}:{payload_str}"
signature = hmac.new(
client_secret.encode("utf-8"),
msg=data_to_sign.encode("utf-8"),
digestmod=hashlib.sha256
).digest()
signature_base64 = base64.b64encode(signature).decode("utf-8")
# the following should result in `True` if the signatures match
valid = secrets.compare_digest(signature_base64, x_pio_hmac_sha256)

バージョン2のWebhook

バージョン2のWebhookでは、ショップのヘッダーが削除され、その他の関連する識別情報がペイロードに含まれるようになっています。

現在、バージョン2のWebhookが使用されているのは出荷実行リクエストのみです。

含まれるヘッダーは次のとおりです。

  • X-Pio-Hmac-Sha256:HMAC-SHA256署名です。
  • X-Pio-Delivery-Id:WebhookのIDです。冪等性を確保するために使用されます。
  • X-Pio-Event-Type:Webhookが参照するイベントの種類です。イベントの種類については、以下の関連セクションで説明します。
  • X-Pio-Timestamp:リクエストが行われた時刻を表す、Unixタイムスタンプです。

PioのWebhookを検証するPythonコードの例は次のとおりです。

import hashlib
import hmac
import base64
import secrets

# your integration's `client_secret`
client_secret: str = <...>
# get the payload from the request
payload: bytes = <...>
payload_str = payload.decode('utf-8')
data_to_sign = f"{x_pio_event_type}:{x_pio_delivery_id}:{x_pio_timestamp}:{payload_str}"
signature = hmac.new(
client_secret.encode("utf-8"),
msg=data_to_sign.encode("utf-8"),
digestmod=hashlib.sha256
).digest()
signature_base64 = base64.b64encode(signature).decode("utf-8")
# the following should result in `True` if the signatures match
valid = secrets.compare_digest(signature_base64, x_pio_hmac_sha256)