Cara Memecahkan Cloudflare Turnstile di PHP Dengan Composer

Cloudflare Turnstile muncul dalam dua bentuk dan keduanya memerlukan PHP yang berbeda. Widget yang berada di dalam formulir adalah panggilan dua argumen. Tantangan interstisial satu halaman penuh memerlukan dua nilai tambahan yang dibaca dari halaman, dan tokennya hanya diterima jika Anda mengirimkan kembali user agent yang digunakan pemecah. Lewatkan bagian terakhir itu dan Anda mendapat token yang terlihat sepenuhnya valid tetapi selalu ditolak.
Yang mana yang sedang Anda lihat?
| Widget | Halaman challenge | |
|---|---|---|
| Tampilan | Kotak centang di formulir yang masih bisa Anda gunakan | Interstisial satu halaman penuh, semuanya terblokir |
| Membutuhkan cData dan chlPageData | Tidak | Ya |
| Membutuhkan user agent yang dikembalikan | Tidak | Ya |
Kami demo Turnstile langsung menjalankan varian widget, yang praktis untuk perbandingan.
Penyiapan
# PHP 8.0+, with the curl and json extensions. composer require capskip/capskip
use CapSkip\CapSkip;
$solver = new CapSkip([
'host' => '127.0.0.1',
'port' => 8080,
'recaptchaTimeout' => 300, // seconds, also covers Turnstile
]);CapSkip memecahkan secara lokal, jadi aplikasi desktop harus berjalan sebelum panggilan apa pun berhasil.
Mode widget
$result = $solver->turnstile(
'0x4AAAAAAA...', // the data-sitekey attribute
'https://example.com/login'
);
echo $result['code']; // cf-turnstile-response tokenLetakkan $result['code'] ke dalam cf-turnstile-response tersebut dan kirim formulirnya. Itulah keseluruhan alur untuk widget.
Halaman challenge membutuhkan dua nilai tambahan
Interstitial membawa state per permintaan yang mengikat token, dan dua bagian darinya harus ikut dikirim bersama pemecahan:
- cData, diteruskan sebagai
data - chlPageData, diteruskan sebagai
pagedata
Keduanya berada di dalam halaman tantangan, bukan di atribut formulir, sehingga halamannya harus diambil sebelum dapat dipecahkan. Pada interstisial Cloudflare standar, keduanya berada pada objek opsi tantangan milik halaman itu sendiri bersama sitekey. Keduanya sekali pakai dan terikat pada pemuatan halaman tersebut, jadi ambil dan pecahkan sekaligus alih-alih menyimpannya di cache.
$result = $solver->turnstile($sitekey, $pageUrl, [
'data' => $cData, // the cData value from the page
'pagedata' => $chlPageData, // the chlPageData value
'action' => 'managed', // optional, when the page declares one
]);
echo $result['code'];
echo $result['userAgent']; // needed for the submitUser agent wajib di sini
Turnstile mengikat token ke fingerprint browser yang menghasilkannya, dan user agent adalah bagian dari fingerprint itu. CapSkip mengembalikan nilai yang dipakainya di $result['userAgent']. Kirim dengan user agent bawaan cURL dan Cloudflare akan menolak token yang sebenarnya sepenuhnya baik.
userAgent hanya terisi untuk Turnstile. Nilainya tidak ada untuk setiap tipe CAPTCHA lain, itulah sebabnya hal ini menjebak orang yang memakai ulang helper reCAPTCHA yang sudah bekerja.
$ch = curl_init($pageUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
// Send back the exact user agent the solve was performed with.
CURLOPT_USERAGENT => $result['userAgent'],
CURLOPT_POSTFIELDS => http_build_query([
'cf-turnstile-response' => $result['code'],
]),
]);
$response = curl_exec($ch);
curl_close($ch);Jika sebuah token ditolak dan cData-nya masih baru, ini hampir selalu penyebabnya.
Proxy
$result = $solver->turnstile($sitekey, $pageUrl, [
'data' => $cData,
'pagedata' => $chlPageData,
'proxy' => ['type' => 'HTTPS', 'uri' => 'user:[email protected]:3128'],
]);Pecahkan melalui jalur keluar yang sama dengan yang akan Anda pakai untuk mengirim ketika tantangannya sensitif terhadap lokasi. Proxy berfungsi untuk Turnstile, reCAPTCHA, dan GeeTest, tetapi tidak untuk CAPTCHA gambar, yang tidak pernah menyentuh situs target.
Kesalahan
use CapSkip\Exceptions\ApiException;
use CapSkip\Exceptions\NetworkException;
use CapSkip\Exceptions\TimeoutException;
try {
$result = $solver->turnstile($sitekey, $pageUrl, $options);
} catch (NetworkException $e) {
// CapSkip is not running on the configured port
} catch (ApiException $e) {
// often a stale cData, since it is bound to one page load
} catch (TimeoutException $e) {
// exceeded recaptchaTimeout
}Semuanya berada di bawah CapSkip\Exceptions, tidak seperti SDK Python dan Node yang mengekspor exception dari root paket.
Pertanyaan yang sering diajukan
Apakah widget pernah membutuhkan cData?
Tidak, dan mengirim nilai kosong justru membuat pemecahan gagal alih-alih membantu. Hanya tantangan interstitial satu halaman penuh yang menggunakannya.
Token saya valid tetapi ditolak.
Hampir selalu user agent. Atur CURLOPT_USERAGENT ke $result['userAgent'] alih-alih membiarkan nilai bawaan cURL. Penyebab paling mungkin berikutnya adalah cData yang basi, yang hanya bertahan satu kali muat halaman.
Haruskah ini berjalan di dalam permintaan web?
Sebaiknya tidak. PHP bersifat sinkron dan pemecahan Turnstile memakan beberapa detik, jadi melakukannya saat render halaman akan memblokir sebuah worker. Pindahkan ke job antrean atau worker CLI.
Ringkasan
Widget memerlukan sitekey dan URL halaman. Halaman challenge memerlukan data dan pagedata dibaca baru dari halaman, dan token harus dikirim bersama $result['userAgent']. Impor exception dari CapSkip\Exceptions, dan jauhkan pemecahan dari thread permintaan Anda.
Bahasa lain ada di Pemecah Cloudflare Turnstile halaman, detail parameter di dokumentasi API, dan cakupan PHP yang lebih luas ada di halaman pemecah CAPTCHA PHP halaman. CapSkip adalah pemecah captcha tanpa batas berjalan di komputer Anda sendiri.
