Webhook設定

Webhook設定

お知らせ:当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。

Webhookは、特定のイベントが発生したときに、Zoho Webセミナーから外部アプリケーションへ即座に通知するための仕組みです。ワークフローでトリガーが実行されると、Webhookはイベントデータを含むPUTまたはPOST要求を、指定したURLに送信します。
Zoho Webセミナーでは、Webhookはワークフローの設定内で、すぐに実行する処理または予約処理として直接設定します。処理の種類としてWebhookを選択すると、ワークフロー内に設定フォームが表示され、必要な詳細を入力できます。

 Webhookの設定方法  

設定するには、以下の手順に従ってください。
Webhookはワークフローの処理の一部です。Webhookを使用するには、ワークフローを作成します。
  1. ワークフロー内でこのWebhookを識別するための名前を入力します。
  2. メソッドはデフォルトでPOSTに設定されており、必要に応じてPUTに変更できます。
  3. 受信側アプリケーションから提供されたWebhook URLを入力します。
  4. 必要に応じて説明を追加し、このWebhookの目的をメモします。
  5. 認証タイプ(一般、接続、署名)を選択します。選択したタイプを必要に応じて設定します。
  6. 送信するイベントデータを含む本文をJSON形式で追加します。
  7. [+ 追加]をクリックし、パラメーターのキーと値の組み合わせを入力して、クエリーを追加します。
  8. [+ パラメーターの追加]をクリックし、キーと値の組み合わせを入力して、必要なヘッダーを追加します。
  9. [保存]をクリックしてWebhook設定を適用し、ワークフローの設定を完了します。

   

 認証タイプ  

Zoho Webセミナーでは、Webhookを保護するために3つの認証オプションを利用できます。受信側アプリケーションの要件に合うものを選択してください。

一般

一般認証では、Webhookに基本的な認証レベルを設定できます。受信側アプリケーションが受信要求の確認にシンプルな認証情報を必要とする場合に使用します。

接続

接続認証では、Webhookを[接続]タブで設定済みの既存の接続に関連付けます。認証情報を手動で入力する代わりに、事前に認証済みの接続を選択すると、Webhookは保存済みの認証情報を使用して受信側アプリケーションで認証を行います。

署名

署名認証では、自動生成されたシークレットトークンを使用して各Webhook要求に署名します。受信側アプリケーションはこのトークンを使用して、要求が実際にZoho Webセミナーから送信されたものであり、送信中に改ざんされていないことを確認します。
  • トークンはZoho Webセミナーによって自動生成されます

  • [コピー]をクリックしてトークンをコピーし、受信側アプリケーションに追加します

  • 現在のトークンが漏洩した場合は、[再生成]をクリックして新しいトークンを作成します。再生成すると、以前のトークンは直ちに無効になります。

 本文  

本文には、Zoho Webセミナーが各Webhook要求で受信側アプリケーションに送信するデータペイロードが含まれます。ペイロードは次の2つの形式のいずれかで送信できます。

JSON

JSON形式は、受信側アプリケーションが構造化された機械判読可能なデータを想定している場合に使用します。ペイロードは、送信するイベントデータを表すキーと値の組み合わせを含むJSONオブジェクトとして記述します。

フォームデータ

フォームデータ形式は、受信側アプリケーションがURLエンコードされた文字列として送信されるペイロードを想定している場合に使用します。各値はURLエンコードされ、組み合わせは&で連結されます。

WebセミナーのWebhook要求の検証

サービスが受信するWebhook要求が実際にZoho Webセミナーから送信されたものであり、送信中に改ざんされていないことを確認するため、署名認証で送信されるすべての要求には`X-Webセミナー-SIGNATURE`ヘッダーが含まれます。
このヘッダーはHMAC SHA-256ハッシュであり、組織の署名キー(シークレット)と未加工の要求本文を組み合わせて計算されます。エンドポイント側で、要求本文とシークレットからハッシュを再計算し、ヘッダー内の値と比較します。2つが一致する場合、要求は検証に合格しています。一致しない場合、要求が改ざんされている可能性があります。

 

送信された本文

{'webinarId':'12345','event':'registration','メール':'ユーザー@例.com'}

  

ヘッダー。

X-Webセミナー-SIGNATURE: a1b2c3d4e5f6...

Content-Type: application/json

 

サンプルコード。

Node.js

const crypto = require('crypto');

 

/**

* Verifies an X-Webセミナー-SIGNATURE header. Works for both JSON and

* form-data webhooks — just pass the raw 要求 body.

*

* @param {string} rawBody Raw HTTP 要求 body as received (JSON text or

* url-encoded form string); never parsed/re-serialized.

* @param {string} signatureHeader Value of the X-Webセミナー-SIGNATURE header.

* @param {string} secret The org's Webhook signature key (token).

* @returns {boolean} True if the signature is valid.

*/

function verifySignature(rawBody, signatureHeader, secret) {

if (!signatureHeader || !secret) {

return false;

}

 

const body = rawBody || '';

const expected = crypto

.createHmac('sha256', secret)

.update(body, 'utf8')

.digest('hex'); // lowercase hex

 

const expectedBuf = Buffer.from(expected, 'utf8');

const receivedBuf = Buffer.from(signatureHeader.trim().toLowerCase(), 'utf8');

 

// Lengths must match for timingSafeEqual

if (expectedBuf.length !== receivedBuf.length) {

return false;

}

return crypto.timingSafeEqual(expectedBuf, receivedBuf);

}

 

// Example usage

const secret = 'your-Webhook-signature-token';

 

// JSON Webhook: rawBody is the JSON text as received

const jsonBody = '{'name':'Ann','id':42}';

 

// Form-data Webhook: rawBody is the url-encoded form string as received

const formBody = 'name=Ann&メモ=hi+there';

 

const signatureFromHeader = '...'; // X-Webセミナー-SIGNATURE value

 

const isValid = verifySignature(jsonBody, signatureFromHeader, secret);

console.log(isValid ? 'Signature is valid!' : 'Signature is invalid!');

Python

インポート hmac

インポート hashlib

 

 

def verify_signature(raw_body: str, signature_header: str, secret: str) -> bool:

'''

Verifies an X-Webセミナー-SIGNATURE header. Works for both JSON and

form-data webhooks -- just pass the raw 要求 body.

 

:param raw_body: Raw HTTP 要求 body as received (JSON text or

url-encoded form string); never parsed/re-serialized.

:param signature_header: Value of the X-Webセミナー-SIGNATURE header.

:param secret: The org's Webhook signature key (token).

:return: True if the signature is valid.

'''

if not signature_header or not secret:

return False

 

body = raw_body or ''

expected = hmac.new(

secret.encode('utf-8'),

body.encode('utf-8'),

hashlib.sha256,

).hexdigest() # lowercase hex

 

# Constant-time comparison (header normalized to lowercase)

return hmac.compare_digest(expected, signature_header.strip().lower())

 

 

# Example usage

if __name__ == '__main__':

secret = 'your-Webhook-signature-token'

 

# JSON Webhook: raw_body is the JSON text as received

json_body = '{'name':'Ann','id':42}'

 

# Form-data Webhook: raw_body is the url-encoded form string as received

form_body = 'name=Ann&メモ=hi+there'

 

signature_from_header = '...' # X-Webセミナー-SIGNATURE value

 

is_valid = verify_signature(json_body, signature_from_header, secret)

print('Signature is valid!' if is_valid else 'Signature is invalid!')

Java

インポート javax.crypto.Mac;

インポート javax.crypto.spec.SecretKeySpec;

インポート java.nio.charset.StandardCharsets;

インポート java.security.MessageDigest;

 

public class WebinarSignatureValidator {

 

/**

* Verifies an X-Webセミナー-SIGNATURE header. Works for both JSON and

* form-data webhooks — just pass the raw 要求 body.

*

* @param rawBody the raw HTTP 要求 body as received (JSON text or

* url-encoded form string); never parsed/re-serialized

* @param signatureHeader value of the X-Webセミナー-SIGNATURE header

* @param secret the org's Webhook signature key (token)

* @return true if the signature is valid

*/

public static boolean verifySignature(String rawBody, String signatureHeader, String secret) {

if (signatureHeader == null || signatureHeader.isEmpty() || secret == null) {

return false;

}

try {

String body = rawBody != null ? rawBody : '';

Mac mac = Mac.getInstance('HmacSHA256');

mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), 'HmacSHA256'));

byte[] raw = mac.doFinal(body.getBytes(StandardCharsets.UTF_8));

 

StringBuilder hex = new StringBuilder(raw.length * 2);

for (byte b : raw) {

hex.append(Character.forDigit((b >>> 4) & 0xF, 16));

hex.append(Character.forDigit(b & 0xF, 16));

}

String expected = hex.toString();

 

// Constant-time comparison (header normalized to lowercase)

return MessageDigest.isEqual(

expected.getBytes(StandardCharsets.UTF_8),

signatureHeader.trim().toLowerCase().getBytes(StandardCharsets.UTF_8));

} catch (Exception e) {

return false;

}

}

 

// Example usage

public static void main(String[] args) {

String secret = 'your-Webhook-signature-token';

 

// JSON Webhook: rawBody is the JSON text as received

String jsonBody = '{\'name\':\'Ann\',\'id\':42}';

 

// Form-data Webhook: rawBody is the url-encoded form string as received

String formBody = 'name=Ann&メモ=hi+there';

 

String signatureFromHeader = '...'; // X-Webセミナー-SIGNATURE value

 

boolean valid = verifySignature(jsonBody, signatureFromHeader, secret);

System.out.println(valid ? 'Signature is valid!' : 'Signature is invalid!');

}

}