Laravel - StripeのWebhookで署名チェックする

stripe + webhookを実装しようと日本語記事を読んだら、どれも署名とか認証チェックみたいなことが考慮されていないので不安になって調べたメモ。

CSRFトークンのチェックを無効にしておく

本題とは関係ないけど、CSRFを無効にしておかないと302エラーになる。
なのでVerifyCsrfToken$exceptにwebhookのエンドポイントを入れておく。

<?php
# app/Http/Middleare/VerifyCsrfToken.php
# ...
    protected $except = [
        # こんな感じで無効にするエンドポイントを追加
        'stripe/wh/*',
    ];
# ...

署名チェックの実装

Stripeは公式ドキュメントが本当によく出来ていて、そこにそのまま書いてある。
Checking Webhook Signatures | Stripe

サンプルコードも載っているので特に補足もないけど、Laravelで書くならこんな感じ。

<?php
# ...
try {
    $content   = $req->getContent();
    $signature = $req->header('Stripe-Signature');
    // stripeのwebhook管理画面から取得した署名(configには自分で追加する必要あり)
    $wh_secret = config('services.stripe.webhook_secret');
    $event     = \Stripe\Webhook::constructEvent($content, $signature, $wh_secret);

    // $eventを使った何かしらの処理

    // レスポンスは何でもいいけど、管理画面上の表示が見やすいのでjsonにしている
    return response()->json('ok', 200);
} catch(\UnexpectedValueException $e) {
    return response()->json('Invalid payload', 400);
} catch(\Stripe\Error\SignatureVerification $e) {
    return response()->json('Invalid signature', 400);
} catch(\Throwable $e) {
    return response()->json($e->getMessage(), 500);
}
# ...

IPホワイトリストでもチェックできそう

実際に動作確認はしていないけどwebhookはこれらのIPから来るとか。
Domains and IP Addresses | Stripe