Webhookをより安全に利用する
  • 31 Mar 2022
  • 1 分で読めます
  • 投稿者
  • ダーク
    ライト

Webhookをより安全に利用する

  • ダーク
    ライト

記事の要約

はじめに

Webhook URLを設定した場合、そのURLへのリクエストが実際にAutifyから送られたものかどうかを確認するためにWebhookシークレットも併せて設定することを推奨します。このドキュメントではWebhookシークレットがない場合のリスクや、生成・設定・確認方法について説明します。

Webhookシークレットとは

Webhook URLはインターネット上に公開する必要があります。そのため、そのURLに対するリクエストが、常にAutifyから送信されているという保証はどこにもありません。また、中間者攻撃などにより、Webhookのリクエストが改ざんされてしまう可能性もあります。

これらのリスクに対応するために、ユーザーはWebhookシークレットを設定することができます。Webhookシークレットとは、受け取ったWebhookリクエストを検証するために、ユーザーとAutifyだけが共有する任意の文字列(秘密鍵)のことです。この値はユーザーが作成してAutifyに設定する必要があります。

Autifyとユーザーは、同じWebhookシークレットを使って、同じアルゴリズムで ペイロード(ここではHTTPリクエストのボディ全文を指します)の HMAC (暗号化された文字列)を生成します。この2つを比較することで、ユーザーは以下のことを確認することができます。

  • リクエストの送信元が、Webhookシークレットを 知っている こと。Webhookシークレットを、Autifyとユーザー以外の第三者に誤って公開しない限り、受信したリクエストが間違いなくAutifyからのものであると確認できます。
  • 送信されたリクエストが 改ざんされたものでない こと。HMACは、リクエストを送信した時点で生成されたものなので、リクエストが送信されてからWebhook URLに届くまでの経路で改ざんされていないと確認できます。

Webhookシークレットを使ったリクエストの検証

Webhookシークレットを設定すると、AutifyからのリクエストヘッダにX-Autify-Signatureが含まれます。この値は、AutifyがリクエストとWebhookシークレットを用いて生成したハッシュ値です。

Webhookシークレットの生成及び設定方法

  1. ワークスペース設定ページのWebhookセクションで新規作成、もしくは既存のものを選択
  2. Webhookシークレットを生成。値はランダムに生成するなど、推測されにくいものを使用してください。以下は、コマンドラインによるランダム値の生成方法です。
# ランダム値の生成例
$ openssl rand -hex 20b2f82af62f9980f6b01e1cd7e716230d0a063f58
  1. Webhookシークレットに前のステップで取得した値を入力
  2. 作成または更新ボタンを押下

Webhookシークレットを用いたペイロードの検証方法

以下のように、ペイロードのHMACを生成し、リクエストヘッダに記載されたものと比較します。

  1. Webhookシークレットを用いてペイロードのHMACを計算
  2. (1)で取得した値をsha1=の末尾に結合
  3. 受け取ったリクエストヘッダX-Autify-Signatureの値を取得
  4. (2)と(3)で取得した値を比較して一致することを確認
    • ※ 値が一致しない場合、Autify以外からのリクエストの可能性があります。

以下は各言語での確認方法のサンプルです:

Ruby

$ gem install rack
require 'openssl'
require 'rack'

digest = OpenSSL::HMAC.hexdigest(
  OpenSSL::Digest.new('sha1'),
  '<Webhookシークレット>',
  '<ペイロード>'
)

computed_signature = "sha1=${digest}"
request_signature  = '<X-Autify-Signature>'

Rack::Utils.secure_compare(
  computed_signature, 
  request_signature
)

Node.js

const crypto = require('crypto');

const digest = crypto
  .createHmac('sha1','<Webhookシークレット>')
  .update('<ペイロード>')
  .digest('hex')

const computedSignature = `sha1=${digest}`
const requestSignature  = '<X-Autify-Signature>'

crypto.timingSafeEqual(
  Buffer.from(computedSignature, 'utf8'), 
  Buffer.from(requestSignature, 'utf8')
)

この記事は役に立ちましたか?

Changing your password will log you out immediately. Use the new password to log back in.
First name must have atleast 2 characters. Numbers and special characters are not allowed.
Last name must have atleast 1 characters. Numbers and special characters are not allowed.
Enter a valid email
Enter a valid password
Your profile has been successfully updated.