Cara Mengatasi Blokir TLS Fingerprinting di Python Requests

tls fingerprinting - How to Fix TLS Fingerprinting Blocks in Python Requests

Jika header Anda sudah sempurna dan situs tetap memblokir Anda, pemblokiran itu terjadi sebelum header pertama Anda bahkan sampai. TLS fingerprinting mengidentifikasi HTTP client Anda dari bentuk TLS handshake-nya, dan library requests di Python memiliki handshake yang tidak diproduksi oleh browser mana pun di dunia. Anda tidak bisa memperbaikinya dengan menyalin string user agent. Anda memperbaikinya dengan membuat handshake itu sendiri terlihat seperti browser. Tulisan ini menunjukkan cara membaca fingerprint Anda sendiri, cara mengubahnya, dan cara membedakan masalah ini dari dua masalah lain yang sering tertukar dengannya.

Apa yang Anda butuhkan

  • Python 3.10 atau lebih baru. Contoh-contoh di sini menggunakan library requests terlebih dahulu untuk menunjukkan masalahnya, lalu curl_cffi untuk memperbaikinya.
  • Terminal dan sekitar sepuluh menit. Langkah diagnostik hanya memerlukan dua request dan tidak perlu perubahan kode.
  • CapSkip yang berjalan, hanya untuk bagian terakhir, baik dalam mode Local di alamat loopback maupun dalam mode Server di komputer yang dapat dijangkau oleh worker Anda. Kedua mode ini dijelaskan pada pengaturan koneksi, jadi pilih salah satu sebelum Anda mulai.

Apa sebenarnya yang dibaca oleh TLS fingerprinting

Setiap koneksi TLS dimulai dengan pesan ClientHello. Pesan ini mencantumkan versi TLS yang Anda dukung, cipher suite yang Anda tawarkan, ekstensi yang Anda kirim, elliptic curve yang Anda terima, dan urutan semuanya disusun. Tidak satu pun dari itu bersifat rahasia, dan tidak satu pun bisa dikonfigurasi per request. Semuanya ditentukan oleh library TLS yang menjadi dasar pembuatan HTTP client Anda.

Hash daftar itu dan Anda akan mendapatkan identifier yang stabil untuk perangkat lunak client. JA3 adalah versi hash tersebut yang pertama kali banyak digunakan. JA4 adalah versi yang berlaku saat ini, dan ia mengurutkan ekstensi ClientHello sebelum melakukan hashing sehingga browser yang sama tidak menghasilkan fingerprint yang berbeda pada setiap koneksi. Cloudflare mendeskripsikan keduanya sebagai cara untuk mengidentifikasi TLS client berdasarkan cara mereka memulai koneksi, dan mengekspos nilai tersebut ke firewall rule, ke analytics, dan ke Workers.

Inilah alasan mengapa itu lebih diutamakan daripada header apa pun yang Anda atur. OpenSSL sebagaimana dibawa oleh Python, BoringSSL sebagaimana dibawa oleh Chrome, dan NSS sebagaimana dibawa oleh Firefox, semuanya mengirim pesan ClientHello yang berbeda. Jadi, request yang mengaku sebagai Chrome padahal melakukan handshake seperti Python bukanlah petunjuk halus yang butuh deteksi rumit. Itu adalah dua field yang tidak cocok, dan sebuah bot rule bisa membandingkannya hanya dalam satu baris.

Langkah 1: baca fingerprint Anda sendiri sebelum mengubah apa pun

Jangan menebak-nebak apakah TLS fingerprinting adalah masalah Anda, karena Anda bisa mengukurnya. Ada endpoint publik yang mengembalikan hash JA3 yang terlihat pada koneksi Anda, dan membandingkan dua request terhadapnya hanya butuh waktu kurang dari semenit.

# pip install requests
import requests

# The endpoint echoes back the handshake it received from you.
r = requests.get("https://tls.browserleaks.com/json", timeout=30)
seen = r.json()

print(seen["ja3_hash"])       # stable per TLS library, not per user agent
print(seen["ja3_text"])       # the raw cipher and extension list

Sekarang jalankan lagi panggilan yang sama dengan user agent browser yang diatur di header, lalu baca hash-nya untuk kedua kalinya. Nilainya tidak akan berubah. Itulah keseluruhan pelajaran dalam satu eksperimen: user agent hidup di header, fingerprint hidup di handshake, dan mengubah yang pertama tidak berpengaruh apa pun pada yang kedua. Jika selama ini Anda memutar-mutar user agent untuk melewati pemblokiran, inilah alasan mengapa itu tidak pernah berhasil.

Langkah 2: melakukan handshake seperti browser asli dengan curl_cffi

Anda tidak bisa membuat TLS stack standar Python menghasilkan ClientHello ala Chrome, karena kumpulan ekstensi dan urutannya sudah tertanam pada build library, bukan diekspos sebagai pengaturan. Yang bisa Anda lakukan adalah memakai library lain. Paket curl_cffi terikat pada build curl yang mereproduksi handshake browser tertentu, dan ia mengekspos API yang berbentuk seperti requests sehingga sisa kode Anda hampir tidak perlu berubah.

# One dependency, no browser and no driver involved.
pip install curl_cffi --upgrade

Argumen yang melakukan pekerjaan ini adalah impersonate. Argumen ini memilih build browser mana yang harus ditiru oleh handshake, dan Anda bisa mengunci versi tertentu ketika sebuah situs mulai rewel soal versi yang sedang berlaku.

# pip install curl_cffi
import curl_cffi

# Same call as before, but the handshake now matches Chrome.
r = curl_cffi.get("https://tls.browserleaks.com/json", impersonate="chrome")
print(r.json()["ja3_hash"])   # a different hash from the requests run above

# Pin a version when a site rejects the current default.
r = curl_cffi.get("https://example.com/", impersonate="chrome124")
print(r.status_code)

Bandingkan kedua hash itu berdampingan. Jika keduanya berbeda, impersonation sedang berjalan, dan itulah satu-satunya konfirmasi yang benar-benar berarti. Proyek ini mendokumentasikan target yang didukung, yang mencakup Safari dan build iOS Safari selain Chrome. String JA3 buatan tangan juga diterima, meskipun preset yang terus dipelihara hampir selalu lebih unggul, karena preset diperbarui setiap kali browser diperbarui.

Pindah ke session begitu ini berhasil. Anda menginginkan penggunaan ulang koneksi dan cookie jar, dengan alasan yang sama seperti saat Anda menginginkannya di requests.

# pip install curl_cffi
import curl_cffi

# One session, one handshake profile, cookies carried across calls.
s = curl_cffi.Session(impersonate="chrome")

s.get("https://example.com/login")
r = s.get("https://example.com/dashboard")

print(r.status_code, len(s.cookies))

Langkah 3: jaga konsistensi sisa client Anda

Handshake browser yang melekat pada request yang jelas-jelas terlihat scripted adalah jenis ketidakcocokan tersendiri, dan memperbaiki satu sinyal sementara membiarkan sinyal lain tetap mencolok adalah cara paling umum hal ini menjadi salah. Ada tiga hal yang harus sesuai dengan profil yang Anda pilih.

User agent Anda harus menyebut keluarga browser yang sama dan versi yang kurang lebih sama dengan target impersonation. Mengaku sebagai Firefox padahal melakukan handshake sebagai Chrome lebih buruk daripada tidak mengaku sama sekali, karena itu mengubah sinyal yang lemah menjadi sinyal yang meyakinkan.

Urutan header Anda penting, begitu juga perilaku HTTP/2 Anda. Browser mengirim urutan header yang stabil, sekumpulan settings frame HTTP/2 yang stabil, dan urutan pseudo header yang stabil, dan semuanya bisa di-fingerprint sama jelasnya seperti lapisan TLS. Mengirim header dalam urutan apa pun yang kebetulan dihasilkan oleh iterasi dictionary Anda menghapus semua kerja yang baru saja Anda lakukan. Itu satu alasan lagi untuk memakai preset impersonation yang terus dipelihara, yang menangani lapisan HTTP/2 untuk Anda alih-alih menyerahkannya pada default client Anda.

IP Anda harus masuk akal untuk traffic yang Anda kirim. Alamat datacenter yang mengirim request berbentuk browser dengan kecepatan mesin adalah sinyal tersendiri, dan tidak ada handshake yang bisa memperbaikinya. Ada pembahasan lengkap soal opsi-opsinya di tulisan tentang rotasi proxy CAPTCHA, yang membahas di mana rotasi seharusnya ditempatkan di dalam worker pool.

Mengurutkan sinyal-sinyal ini, agar Anda memperbaikinya sesuai urutan yang benar

SinyalDi mana ia dibacaBisakah Anda mengubahnya
TLS ClientHello, di-hash sebagai JA3 atau JA4Sebelum data HTTP apa pun dikirimYa, dengan mengganti library TLS
Pengaturan HTTP/2 dan urutan pseudo headerFrame pertama dari koneksiYa, dan preset yang baik akan melakukannya untuk Anda
Nama, nilai, dan urutan headerRequest itu sendiriYa, dan ini yang paling mudah salah
Reputasi IP dan jenis alamatSumber koneksiHanya dengan mengubah dari mana Anda terhubung
Sinyal runtime browser seperti canvas dan WebGLDi dalam halaman sungguhan, setelah JavaScript berjalanTidak berlaku saat Anda tidak menjalankan browser
Laju request dan pola navigasiDi banyak requestYa, dengan memperlambat dan memvariasikan path yang Anda tuju

Kerjakan tabel ini dari atas ke bawah, bukan menyamping. TLS fingerprinting terjadi paling awal dalam koneksi, sehingga menjadi tempat termurah bagi pihak bertahan untuk mengambil keputusan, dan menjadi tempat pertama yang harus disasar oleh perbaikan Anda.

Apa yang tidak diperbaiki oleh semua ini

Handshake yang benar bukanlah tiket masuk. Handshake yang benar hanya menghilangkan satu alasan untuk mencurigai Anda, yang berarti situs kini akan mengevaluasi sisa traffic Anda alih-alih langsung menolak Anda di depan pintu. Banyak situs tetap akan menampilkan challenge setelah Anda memperbaiki fingerprint, dan itu adalah hasil yang wajar, bukan tanda bahwa usaha Anda gagal.

Itulah batas yang jujur, dan patut dinyatakan secara terus terang. CapSkip tidak mengubah TLS fingerprint Anda dan bukan lapisan stealth. CapSkip memecahkan CAPTCHA yang disajikan kepada Anda, yaitu bagian dari masalah ini yang berujung pada sebuah token. Jika widget Turnstile atau halaman challenge adalah yang menghalangi Anda dari response body, solver menghasilkan token tersebut dan client Anda yang sudah ada mengirimkannya.

# pip install capskip
from capskip import CapSkip

solver = CapSkip(host="127.0.0.1", port=8080)

# The challenge you were served, solved on your own machine.
result = solver.turnstile(
    sitekey="YOUR_SITEKEY",
    url="https://example.com/protected",
)

token = result["code"]
agent = result["userAgent"]   # send this exact user agent with the token

User agent yang dikembalikan itu bukan sekadar hiasan. Turnstile mengikat token pada identitas browser yang menghasilkannya, sehingga mengirim token yang sepenuhnya valid dengan user agent yang berbeda adalah cara ampuh untuk membuatnya ditolak. Kirim pasangan keduanya bersama-sama dan pengiriman akan diterima. Halaman Pemecah Cloudflare Turnstile ini membahas kasus widget dan kasus halaman challenge secara terpisah, karena keduanya membutuhkan input yang berbeda.

Menjalankan pemecah di server saja

Pekerjaan fingerprint biasanya muncul dalam sebuah worker pool, bukan dalam satu skrip saja, dan sebuah pool tidak berbagi alamat loopback. Pengaturan koneksi mencakup kedua bentuk ini:

ModeMendengarkan diGunakan saat
Lokal127.0.0.1, hanya perangkat ituScraper Anda dan pemecah berjalan di satu mesin
ServerAlamat jaringan atau IP publik AndaWorkers, VPS, atau platform hosted yang memanggil lewat API

Arahkan host SDK ke mesin solver dan tidak ada lagi yang perlu diubah di kode Anda, sehingga satu armada penuh dapat berbagi satu instance. IP publik statis disarankan ketika pemanggil berada di luar jaringan Anda sendiri. Detailnya ada di pengaturan koneksi, dan mode Server tetap berjalan di hardware Anda sendiri dan tetap tanpa meteran: yang berubah hanya di mana solver berjalan, bukan siapa pemiliknya.

FAQ

Bisakah saya mengubah TLS fingerprint dari library requests itu sendiri?

Tidak secara berarti. Anda bisa mengurutkan ulang cipher suite lewat SSL context yang mendasarinya dan mengubah hash-nya, tetapi Anda tidak bisa mereproduksi ClientHello ala browser dengan cara itu, karena kumpulan ekstensi dan urutannya berasal dari build library, bukan dari konfigurasi. Yang Anda dapatkan pada akhirnya adalah fingerprint yang tidak cocok dengan apa pun, yang justru posisinya lebih buruk daripada cocok dengan Python. Gantilah library-nya saja.

Apakah menjalankan browser sungguhan menghilangkan masalah ini?

Ya, untuk lapisan TLS, karena Chrome sungguhan mengirim handshake Chrome sungguhan. Tetapi ini juga menghabiskan ratusan megabyte per worker dan membuat request jauh lebih lambat, sehingga menjadi jawaban yang berat untuk masalah yang sempit. Gunakan browser ketika Anda benar-benar membutuhkan halaman untuk menjalankan JavaScript, dan gunakan HTTP client yang melakukan impersonation ketika Anda hanya membutuhkan response body.

Bagaimana saya tahu pemblokiran itu karena fingerprinting dan bukan rate limiting?

Perlambat secara signifikan dan coba lagi dari client yang sama. Rate limit akan mengendur setelah Anda menunggu, biasanya memberi tahu berapa lama harus menunggu, dan kembali normal setelahnya. Pemblokiran TLS fingerprinting sama sekali tidak peduli soal waktu, sehingga request pertama hari itu gagal persis seperti request keseratus. Jika sebuah client yang baru pertama kali terhubung sudah gagal pada request pertamanya, menunggu bukanlah solusi Anda.

Apakah CapSkip mengubah fingerprint JA3 atau JA4 saya?

Tidak, dan memang seharusnya tidak. CapSkip adalah solver: Anda memberikan sebuah challenge dan ia mengembalikan sebuah token, berjalan di hardware milik Anda sendiri dan tanpa biaya per pemecahan. Fingerprint Anda adalah milik client yang membuat request, jadi bagian itu tetap menjadi tugas Anda. Kedua bagian ini saling melengkapi dengan baik dalam praktiknya, karena client yang berbentuk browser akan disajikan challenge yang bisa dipecahkan, bukan penolakan mentah-mentah.

Versi paling singkatnya

Baca fingerprint Anda terlebih dahulu, karena hanya butuh satu request untuk menyelesaikan perdebatannya. Jika hash-nya tidak pernah berubah walau Anda memutar-mutar user agent, handshake-lah masalahnya dan tidak ada header yang bisa memperbaikinya. Beralihlah ke client yang melakukan impersonation, jaga agar user agent, urutan header, dan profil HTTP/2 tetap konsisten dengan apa pun yang Anda tiru, lalu periksa IP Anda. Munculnya sebuah challenge setelah itu adalah kemajuan, bukan kegagalan, dan sebuah pemecah captcha lokal adalah bagian yang mengubahnya menjadi token. Catatan tentang cara memasangnya ke dalam worker pool ada di Pemecah CAPTCHA untuk web scraping. Ketika Anda sampai ke kodenya sendiri, halaman pemecah captcha Python memuat detail SDK yang akan Anda butuhkan selanjutnya.