Laravel bật CSRF trên mọi web route. Nhà cung cấp webhook gửi POST không có session cookie hay CSRF token — bạn nhận 419 trước khi controller chạy. Giải pháp: miễn CSRF có chọn lọc và đọc raw body qua $request->getContent().
Miễn CSRF cho route webhook
Thêm URI vào mảng $except trong App\Http\Middleware\VerifyCsrfToken (Laravel 11+: middleware trong bootstrap/app.php):
protected $except = [
'webhooks/stripe',
'webhooks/*',
];
Chỉ miễn path server-to-server — không tắt CSRF toàn app.
Đọc raw body để xác minh chữ ký
Sau khi bỏ qua CSRF, đọc byte nguyên vẹn:
public function handle(Request $request)
{
$payload = $request->getContent(); // raw string
$signature = $request->header('Stripe-Signature', '');
if (!$this->verifySignature($payload, $signature)) {
return response('', 401);
}
$event = json_decode($payload, true, 512, JSON_THROW_ON_ERROR);
$this->processEvent($event);
return response('', 200);
}
Dùng getContent(), không dùng all() hay input() — helper Laravel không trả byte đã ký.
Xác minh chữ ký trước logic nghiệp vụ
Trích header, tính digest từ raw payload, so sánh bằng hash_equals. Sai trả 401. Xem hướng dẫn xác minh chữ ký.
Thiết lập tunnel
- Chạy Laravel:
php artisan serve --port=8000. - Terminal thứ hai:
npx portpreview 8000. - Dán URL tunnel + path vào dashboard.
- Với
TrustProxies, tin header forwarded từ tunnel. - Kích hoạt sự kiện thử.
Bẫy thường gặp
Đọc body hai lần
getContent() sau json() rỗng. Đọc một lần, xác minh, parse.
Thứ tự middleware
Middleware parse JSON trước controller làm đổi byte. Tách route webhook.
Retry và idempotency
Lưu event ID — xem mẫu retry và idempotency.
Đọc thêm
Đọc thêm về cơ bản về localhost tunneling và gỡ lỗi webhook cục bộ. Cơ chế chữ ký xem hướng dẫn xác minh chữ ký. Handler chống trùng lặp xem mẫu retry và idempotency. bắt đầu PortPreview miễn phí.
