Webhook設定

Webhook設定

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

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

Webhookを設定するには

Webhookはワークフローの処理の一部です。Webhookを使用するには、ワークフローを作成します。
ワークフローを設定するには、以下の手順を実行します。
  1. ワークフロー内でこのWebhookを識別するための名前を入力します。
  2. [メソッド]は標準でPOSTに設定されていますが、必要に応じてPUTに変更できます。
  3. 受信側アプリケーションから提供された[Webhook URL]を入力します。
  4. このWebhookの目的を記録するため、任意の説明を追加します。
  5. 認証方式として、[一般]、[外部連携]、または[署名]を選択します。選択した方式を必要に応じて設定します。
  6. 送信するイベントデータを含む本文をJSON形式で追加します。
  7. [+ 追加]をクリックし、クエリパラメーターのキーと値のペアを入力してクエリを追加します。
  8. + パラメーターを追加]をクリックし、キーと値のペアを入力してヘッダーを追加します。
  9. [保存]をクリックしてWebhookの設定を適用し、ワークフローの設定を完了します。

   

 認証方式 

Zoho Webinarでは、Webhookを保護するために3種類の認証方式を利用できます。受信側アプリケーションの要件に合う方式を選択します。

一般

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

外部連携

外部連携認証では、Webhookを外部連携機能で設定済みの外部連携に関連付けます。認証情報を手動で入力する代わりに、事前認証済みの外部連携を選択すると、Webhookは保存されている認証情報を使用して受信側アプリケーションとの認証を行います。

署名

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

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

  • 現在のトークンが漏えいした場合は、[もう一度生成する]をクリックして新しいトークンを作成します。もう一度生成すると、前のトークンはすぐに無効になります。

 本文 

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

JSON

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

フォームデータ

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

Zoho WebinarのWebhook要求の検証

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

 

送信された本文

{'webinarId':'12345','event':'registration','email':'user@example.com'}

  

ヘッダー。

X-WEBINAR-SIGNATURE: a1b2c3d4e5f6...

Content-Type: application/json

 

サンプルコード。

Node.js

const crypto = require('crypto');

 

/**

* Verifies an X-WEBINAR-SIGNATURE header. Works for both JSON and

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

*

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

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

* @param {string} signatureHeader Value of the X-WEBINAR-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&note=hi+there';

 

const signatureFromHeader = '...'; // X-WEBINAR-SIGNATURE value

 

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

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

Python

import hmac

import hashlib

 

 

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

'''

Verifies an X-WEBINAR-SIGNATURE header. Works for both JSON and

form-data webhooks -- just pass the raw request body.

 

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

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

:param signature_header: Value of the X-WEBINAR-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&note=hi+there'

 

signature_from_header = '...' # X-WEBINAR-SIGNATURE value

 

is_valid = verify_signature(json_body, signature_from_header, secret)

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

Java

import javax.crypto.Mac;

import javax.crypto.spec.SecretKeySpec;

import java.nio.charset.StandardCharsets;

import java.security.MessageDigest;

 

public class WebinarSignatureValidator {

 

/**

* Verifies an X-WEBINAR-SIGNATURE header. Works for both JSON and

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

*

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

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

* @param signatureHeader value of the X-WEBINAR-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&note=hi+there';

 

String signatureFromHeader = '...'; // X-WEBINAR-SIGNATURE value

 

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

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

}

}