Skip to main content

ArtinTech Solution

Stripe webhooks failing with 403 behind Cloudflare and the fix

E-mel itu tiba pada pagi Ahad, dimajukan oleh pengarah operasi sebuah yayasan bukan untung di Eropah dengan satu baris sahaja: sila lihat di bawah untuk makluman dan tindakan. Di bawahnya ada mesej automatik daripada Stripe. Sudah beberapa hari Stripe tidak dapat menghantar acara webhook ke laman derma, sembilan belas percubaan gagal, dan jika tiada perubahan, Stripe akan berhenti menghantar pemberitahuan ke endpoint itu dalam masa seminggu.

Bagi organisasi yang menerima derma sekali dan bulanan melalui WordPress, ini bukan amaran kecil. Webhook ialah cara laman web mengetahui bahawa sesuatu bayaran benar-benar berjaya. Tanpanya, derma kekal tertunda, penderma tidak menerima resit dan pembaharuan bulanan tidak direkodkan, walaupun wang terus masuk ke Stripe.

Inilah kisah bagaimana kami menjejaki kegagalan itu, mengapa masalah pertama yang ditemui memang benar tetapi bukan puncanya, dan perubahan kecil yang membetulkannya tanpa mematikan sebarang perlindungan keselamatan.

Apa fungsi webhook Stripe dan mengapa kegagalannya penting

Apabila penderma membayar, pelayar dihantar ke Stripe dan kembali semula. Laman web tidak boleh mempercayai apa yang dikatakan pelayar tentang bayaran, jadi Stripe juga memanggil laman secara terus, dari pelayan ke pelayan, dengan acara seperti payment_intent.succeeded. Laman mesti membalas dengan status HTTP antara 200 hingga 299. Selain itu dikira gagal, dan Stripe akan mencuba semula dengan jarak masa yang semakin panjang sehingga tiga hari sebelum meninggalkan acara tersebut.

Dalam kes ini, plugin derma ialah GiveWP, yang mendengar pada alamat berakhir dengan ?give-listener=stripe. Laman ini berbilang bahasa, jadi terdapat dua endpoint aktif, satu di bawah /de/ dan satu lagi di bawah /fr/. Kedua-duanya gagal, walaupun e-mel Stripe hanya menyebut satu.

Log penghantaran webhook menunjukkan ralat 403 berulang
Setiap percubaan penghantaran sejak awal bulan memulangkan 403. (Ilustrasi, butiran dirahsiakan.)

Penemuan pertama: masalah sebenar, tetapi bukan puncanya

Papan pemuka WordPress terus menunjukkan ralat pengaktifan. Add-on Recurring Donations telah dimatikan kerana ia memerlukan versi GiveWP yang lebih baharu daripada yang dipasang. Add-on itu sudah dikemas kini tetapi plugin utama belum, lalu WordPress mematikannya secara senyap. Lesennya juga tidak akan diperbaharui, jadi ia tidak lagi menerima kemas kini.

Ia kelihatan seperti penjelasan yang sempurna, dan memang perlu dibetulkan. Kami membuat sandaran penuh, mengemas kini GiveWP dan mengaktifkan semula add-on. Bahagian hadapan laman serta-merta rosak dengan ralat fatal. Jejak ralat menunjuk kepada popup yang mengandungi shortcode borang derma lama yang sudah tidak wujud. Kami mematikan add-on untuk memulihkan laman, membetulkan popup, mengaktifkannya semula dan menyemak halaman utama, halaman derma serta setiap versi bahasa.

Laman kembali sihat dan pilihan derma bulanan sudah kembali. Namun webhook masih gagal.

Membaca ralat sebenar dan bukan meneka

Cara paling pantas untuk berhenti meneka ialah membuka satu penghantaran yang gagal dalam Dashboard Stripe, di bawah Developers, Webhooks, dan membaca dua perkara: kod status dan badan respons. Di sini statusnya 403 Forbidden, dan badannya langsung bukan ralat WordPress. Ia ialah halaman HTML bertajuk Just a moment… yang memuatkan skrip dari challenges.cloudflare.com.

Badan respons webhook yang gagal menunjukkan halaman cabaran Cloudflare
Badan respons mendedahkan segalanya: halaman pengesahan manusia daripada CDN, bukan daripada WordPress. (Ilustrasi.)

Halaman itu ialah cabaran pelayar Cloudflare. Ia meminta pelayar membuktikan bahawa ia manusia sebelum permintaan dibenarkan masuk. Manusia yang menggunakan Chrome melepasinya dalam sesaat. Pelayan Stripe bukan pelayar dan tidak boleh menyelesaikan cabaran itu, maka setiap webhook disekat di pinggir rangkaian. Permintaan tidak pernah sampai ke WordPress, sebab itulah tiada apa-apa dalam log laman.

Mencari ciri Cloudflare yang menyekat Stripe

Beberapa ciri Cloudflare boleh mencabar trafik, dan penyelesaiannya bergantung pada ciri mana yang bertanggungjawab. Dalam Security, Analytics, Events, kami menapis rentetan pertanyaan give-listener. Setiap permintaan menunjukkan tindakan Managed Challenge dan perkhidmatan Security level.

Acara keselamatan Cloudflare menunjukkan permintaan webhook disekat oleh Security Level
Panggilan daripada penyedia pembayaran dicabar sama seperti pelawat biasa. (Ilustrasi.)

Senarai yang sama turut menunjukkan perkara lain: pelawat biasa dari Switzerland, Perancis dan Jerman juga dicabar pada halaman biasa. Tahap keselamatan zon telah ditetapkan sangat tinggi, mungkin selepas serangan sebelum ini, dan tiada siapa perasan ia turut menyekat penyedia pembayaran.

Penyelesaian: peraturan Skip yang sempit, bukan laman yang lebih lemah

Menurunkan tahap keselamatan memang berkesan, tetapi ia mengubah perlindungan seluruh laman untuk menyelesaikan masalah satu URL sahaja. Jawapan yang lebih kemas ialah peraturan tersuai yang hanya membenarkan alamat webhook dan mengekalkan yang lain seperti sedia ada.

  1. Pergi ke Security, Security rules dan cipta custom rule baharu.
  2. Beri nama yang jelas, contohnya Allow Stripe webhooks.
  3. Tetapkan syarat: URI Query String, contains, give-listener=stripe.
  4. Pilih tindakan Skip dan tandakan All remaining custom rules.
  5. Buka More components to skip dan tandakan Security Level serta Browser Integrity Check.
  6. Letakkan peraturan di tempat pertama dan aktifkan (Deploy).
(http.request.uri.query contains "give-listener=stripe")
Peraturan Skip Cloudflare untuk give-listener=stripe dengan Security Level ditanda
Peraturan ini hanya untuk pendengar webhook. Security Level mesti ditanda secara jelas kerana itulah ciri yang menyekat. (Ilustrasi.)

Butiran yang mudah terlepas pandang ialah langkah kelima. Versi pertama peraturan hanya melangkau Browser Integrity Check, pratonton API menunjukkan "products": ["bic"], dan webhook akan terus gagal. Log acara menyatakan penyekatnya ialah Security level, jadi komponen itulah yang mesti dilangkau. Nota untuk pelan percuma: jika log menyebut Bot Fight Mode, peraturan Skip tidak dapat memintasnya dan tetapan itu sendiri perlu dimatikan.

Adakah ia selamat? Peraturan ini tidak mempercayai permintaan secara membuta tuli. GiveWP masih mengesahkan setiap webhook dengan kunci tandatangan Stripe, jadi permintaan palsu yang sampai ke pendengar akan ditolak oleh WordPress. Mengesahkan Stripe tidak pernah menjadi tugas Cloudflare; itu tugas tandatangan.

Mengesahkan pembetulan dan memulihkan derma yang tertinggal

Kami menghantar semula satu acara yang gagal dari Dashboard Stripe dan ia kembali dengan 200 OK. Dalam masa sejam, percubaan automatik Stripe mula berjaya dan papan pemuka menandakan kegagalan terdahulu sebagai Delivery recovered. Keesokan harinya Stripe menghantar e-mel mengesahkan endpoint telah pulih.

Penghantaran webhook memulangkan 200 OK selepas pembetulan
Selepas peraturan aktif, penghantaran memulangkan 200 OK dan percubaan semula Stripe menyelesaikan tunggakan. (Ilustrasi.)

Dua perkara praktikal semasa membersihkan. Pertama, butang Resend hanya berfungsi pada percubaan terkini setiap acara, jadi bagi acara yang sudah ditinggalkan Stripe, buka acara itu sendiri dan hantar semula dari situ. Kedua, padankan wangnya, bukan hanya webhook: bandingkan setiap bayaran Stripe sejak gangguan bermula dengan rekod derma dalam WordPress. Dalam kes ini semua bayaran berjaya sudah direkodkan, satu bayaran memang gagal kerana dana tidak mencukupi dan ditandakan gagal, dan dua bayaran ujian kecil semasa siasatan dikenal pasti supaya tiada siapa mengiranya sebagai derma.

Pengajaran untuk mana-mana laman WordPress yang menerima bayaran

  • Baca badan respons dahulu. Ralat 403 yang mengandungi HTML daripada CDN anda bukan pepijat aplikasi, dan nyahpepijat plugin tidak akan membetulkannya.
  • Tetapan keselamatan dan webhook pembayaran mesti selari. Menaikkan tahap keselamatan selepas serangan memang wajar; terlupa bahawa ia juga terpakai pada panggilan pelayan ke pelayan ialah punca derma hilang.
  • Benarkan laluan, bukan seluruh dunia. Peraturan Skip yang sempit pada pendengar mengekalkan perlindungan bahagian lain laman.
  • Lesen add-on yang tamat ialah risiko perlahan. Ia menghentikan kemas kini, dan kemas kini teras seterusnya boleh mematikan add-on tanpa amaran.
  • Pantau amaran. Stripe memberi amaran kira-kira seminggu sebelum mematikan endpoint. Pastikan e-mel itu sampai kepada orang yang boleh bertindak.

Kami pernah menulis tentang kes serupa, apabila cache dan WordPress tidak sepakat tentang masa, dalam ralat 403 berselang-seli akibat TTL cache, serta semakan rutin yang mengesan masalah seperti ini lebih awal dalam apa yang sebenarnya diliputi penyelenggaraan laman web.

Soalan lazim

Mengapa webhook Stripe saya memulangkan 403 sedangkan laman berfungsi dalam pelayar saya?

Kerana pelayar anda boleh melepasi cabaran Cloudflare tetapi pelayan Stripe tidak. Jika badan respons menyebut Just a moment atau challenges.cloudflare.com, permintaan itu disekat di Cloudflare sebelum sampai ke WordPress.

Patutkah saya membenarkan alamat IP Stripe sahaja?

Boleh, menggunakan senarai IP yang diterbitkan Stripe, tetapi senarai itu berubah dan perlu diselenggara. Peraturan Skip pada laluan webhook lebih ringkas dan, kerana plugin mengesahkan tandatangan, sama selamatnya dalam praktik.

Adakah saya kehilangan derma semasa webhook gagal?

Biasanya Stripe tetap mengutip wang, tetapi laman web tidak merekodkannya. Derma kekal tertunda, resit tidak dihantar dan pembaharuan berulang tiada dalam rekod sehingga acara dihantar atau rekod dibetulkan secara manual.

Berapa lama Stripe terus mencuba semula?

Dalam mod langsung, sehingga tiga hari dengan jarak masa yang semakin panjang. Jika endpoint terus gagal, Stripe menghantar amaran melalui e-mel dan akhirnya mematikannya.

Mengendalikan derma, kedai atau keahlian di WordPress dan menerima amaran pembayaran yang mengelirukan? Kami menjalankan siasatan seperti ini sebagai sebahagian daripada perkhidmatan pembangunan WordPress dan penyelenggaraan kami. Hubungi kami dan kami akan memberitahu dengan jelas apa yang rosak dan apa yang diperlukan untuk membetulkannya.

Share this article

Tinggalkan Balasan

Alamat e-mel anda tidak akan disiarkan. Medan diperlukan ditanda dengan *