บทความทั้งหมด
Laravel webhook POST ข้าม CSRF ผ่าน VerifyCsrfToken except ตรวจ byte getContent ด้วย hash_equals บน php artisan serve ในเครื่อง
LaravelPHPwebhook debugginglocal testing

Laravel webhook: ยกเว้น CSRF, raw body และตรวจลายเซ็น

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

  1. รัน Laravel: php artisan serve --port=8000
  2. เทอร์มินัลที่สอง: npx portpreview 8000
  3. วาง URL tunnel + path ใน dashboard
  4. ใช้ TrustProxies ให้เชื่อ header forwarded จาก tunnel
  5. ทริกเกอร์ 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 ฟรี.

คำถามที่พบบ่อย

ทำไม Laravel คืน 419 บน POST webhook?
VerifyCsrfToken ปฏิเสธ POST ที่ไม่มี CSRF token เพิ่ม path webhook ใน $except แล้วตรวจลายเซ็นแทน
ใช้ getContent() หรือ all() สำหรับ webhook?
ใช้ getContent() สำหรับตรวจลายเซ็น all() และ input() คืนข้อมูลที่ parse แล้ว ไม่ใช่ byte ที่เซ็น
ทดสอบ Laravel webhook ในเครื่องอย่างไร?
รัน php artisan serve เปิดด้วย npx portpreview วาง URL tunnel ใน dashboard และทริกเกอร์ event ทดสอบ