Laravel เปิด CSRF บนทุก web route ผู้ให้บริการ webhook ส่ง POST โดยไม่มี session cookie หรือ CSRF token — คุณได้ 419 ก่อนถึง controller แก้ด้วยยกเว้น CSRF และอ่าน raw body ผ่าน $request->getContent()
ยกเว้น webhook route จาก CSRF
เพิ่ม URI ใน $except ของ App\Http\Middleware\VerifyCsrfToken (Laravel 11+: middleware ใน bootstrap/app.php):
protected $except = [
'webhooks/stripe',
'webhooks/*',
];
ยกเว้นเฉพาะ path server-to-server — อย่าปิด CSRF ทั้งแอป
อ่าน raw body สำหรับตรวจลายเซ็น
หลังข้าม CSRF ให้อ่าน byte ดิบ:
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);
}
ใช้ getContent() ไม่ใช่ all() หรือ input() — helper ของ Laravel ไม่คืน byte ที่ถูกเซ็น
ตรวจลายเซ็นก่อน business logic
ดึง header คำนวณ digest จาก raw payload เปรียบเทียบด้วย hash_equals ไม่ผ่านคืน 401 ดู คู่มือตรวจลายเซ็น
ตั้งค่า tunnel
- รัน Laravel:
php artisan serve --port=8000 - เทอร์มินัลที่สอง:
npx portpreview 8000 - วาง URL tunnel + path ใน dashboard
- ใช้
TrustProxiesให้เชื่อ header forwarded จาก tunnel - ทริกเกอร์ event ทดสอบ
กับดักที่พบบ่อย
อ่าน body สองครั้ง
getContent() หลัง json() ว่าง อ่านครั้งเดียว ตรวจ แล้ว parse
ลำดับ middleware
middleware ที่ parse JSON ก่อน controller เปลี่ยน byte แยก webhook route
retry และ idempotency
เก็บ event ID — ดู รูปแบบ retry และ idempotency
อ่านเพิ่ม
พื้นฐานอ่านที่ พื้นฐาน localhost tunneling และ การดีบัก webhook ในเครื่อง. กลไกลายเซ็นอ่านที่ คู่มือตรวจสอบลายเซ็น. handler ป้องกันซ้ำอ่านที่ รูปแบบ retry และ idempotency. เริ่มใช้ PortPreview ฟรี.
