LoginSignup
13
11

More than 3 years have passed since last update.

Webhookとセキュリティ

Last updated at Posted at 2019-09-17

Webhookで決済のような重要なイベントの情報ををやり取りする場合には、リクエストに対する認証完全性が保証されていてほしいです。

認証が保証されていなければ、どんなリクエストを送ればいいかさえわかれば、誰でもなりすましてリクエストができてしまいます。

完全性が保証されていないと、途中でリクエストが改ざんされていてもわかりません。

実装者あるいは利用者として、どのような対策があるのか調べて考えてみました。

考えられる対策

  1. リクエスト自体に認証のための情報を含める
    • ヘッダ
      • Basic認証
      • Bearerトークン
      • etc.
    • パラメータ
    • ボディ
  2. メッセージ認証コードもしくはデジタル署名
対策 認証 完全性
1
2

どのような場合に問題が起きるか

1の場合、リクエスト自体が見れてしまうと任意のメッセージを送れます。また完全性は保証されていません。
2の場合リクエスト自体には鍵が含まれていません。送信時に使う鍵とアルゴリズムがわかると任意のメッセージを送れます。

きちんとした証明書を使ったhttpsであれば、基本リクエスト自体が見られることは無いはずなので、1でも問題ないように思えます。
ただ、以下のようなことをしてしまい、更にその内容が見れるような状態にあると任意のリクエストが送れるようになってしまいます。

  • httpで送ってしまう
  • ログに残ってしまう

簡単に起こり得そうなので基本的には2が好ましいと思います。

しかし2は送信側にもロジックが必要です。自分がWebhook受け取り側で、送信者が2をしてくれない場合には受信側でできることは1になってしまいます。

実際のサービスでの例

触ったことのあるサービスではどのような実装になっているのかいくつか見てみました。

Stripeの場合

  • Checking Webhook Signatures | Stripe
    • Stripe-SignatureヘッダにHMAC(SHA-256)のメッセージ認証コードがついてくる
    • 鍵はendpoint secretとしてwebhook設定から見れる
    • Stripe-Signatureはタイムスタンプも含むことでリプレイ攻撃の対策としている

GitHubの場合

SendGridの場合

結局どうすれば良いのか

実装者として

  • 基本メッセージ認証コードをつける
    • 重要かどうかは受け取り側次第のところがある
    • 将来の仕様変更で重要な情報を含むようになるかもしれない

利用者として

  • 自分にとってそこまで重要ではない情報なら気にしなくていい
  • Webhook提供者がメッセージ認証コードをつけてくれているならその検証をする
    • 基本は提供されているライブラリ、ドキュメントにある実装を使う
    • 自分で検証する場合には定数時間の文字列比較アルゴリズムを使う
      • Timing Attack対策
  • メッセージ認証コードがない場合、予測不可能性を持った乱数で認証トークンを生成してリクエストのURLに設定し検証する
    • 上と同様、文字列比較は定数時間のアルゴリズムを使う
    • URLにBasic認証の情報を含められるなら使う
      • 自分が使っているサービスでは使えないものがあった
    • だめならリクエストパラメータに認証トークンを入れる
      • ログに残らないよう対策する
        • 例えばRailsだったらRails.application.config.filter_parametersに追加する

参考

13
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
11