
Emma Foster
Machine Learning Engineer

Jika pernah mencoba mengambil data dari situs web yang dilindungi oleh deteksi bot tingkat perusahaan, Anda mungkin telah menghadapi dinding tak terlihat: permintaan Anda diblokir meskipun header, cookie, dan User-Agent Anda sempurna. Alasannya? Pemindaian fingerprint TLS — dan terjadi sebelum permintaan HTTP bahkan dikirim.
Layanan anti-bot seperti Cloudflare, Akamai, DataDome, dan lainnya memeriksa handshake TLS mentah untuk menentukan apakah klien adalah browser nyata atau alat otomasi. Klien HTTP standar — Go's net/http, Python's requests, curl, Node.js axios — semuanya memiliki fingerprint TLS yang berbeda yang langsung ditandai.
Dalam panduan ini, Anda akan membangun server Go ringan menggunakan httpcloak yang meniru fingerprint TLS Chrome asli, dan menghubungkannya ke alur kerja n8n sehingga setiap permintaan HTTP terlihat seperti lalu lintas browser Chrome yang asli di tingkat jaringan.
Setiap kali klien terhubung ke situs web melalui HTTPS, ia memulai handshake TLS dengan mengirimkan pesan ClientHello. Pesan ini berisi:
Layanan anti-bot mengambil nilai-nilai ini dan menghitung fingerprint — disebut JA3 atau JA4 — yang secara unik mengidentifikasi perangkat lunak klien. Setiap browser, pustaka HTTP, dan lingkungan bahasa pemrograman menghasilkan fingerprint yang berbeda.
| Klien | Fingerprint JA3 | Diketahui sebagai |
|---|---|---|
| Chrome 145 | Hash unik yang sesuai dengan urutan suite enkripsi Chrome | Browser nyata |
| Firefox 130 | Hash berbeda — Firefox menggunakan preferensi suite enkripsi yang berbeda | Browser nyata |
Go net/http |
Hash yang sama sekali berbeda — stack TLS Go jelas terlihat | Bot / alat otomasi |
Python requests |
Hash unik lainnya — TLS urllib3 Python teridentifikasi |
Bot / alat otomasi |
| curl | Hash lainnya — fingerprint TLS curl dikenal | Bot / alat otomasi |
Node.js axios |
Fingerprint TLS Node.js — mudah ditandai | Bot / alat otomasi |
Kesimpulan utama: Pemindaian fingerprint TLS terjadi selama handshake, sebelum header HTTP dikirim. Tidak ada manipulasi header yang dapat memperbaiki fingerprint TLS yang tidak browser.
Ketika browser terhubung ke situs web melalui HTTPS, ia mengirimkan ClientHello TLS yang mencakup detail tentang suite enkripsi, ekstensi, dan pengaturan yang didukungnya. Layanan anti-bot mencatat fingerprint ini (disebut fingerprint JA3/JA4) dan membandingkannya dengan profil browser yang diketahui.
net/http Go, requests Python, curl, dan sebagian besar pustaka HTTP memiliki fingerprint TLS yang berbeda. Bahkan dengan cookie dan header yang benar, sistem anti-bot akan memblokir permintaan jika mereka mendeteksi fingerprint TLS yang tidak browser.
Berikut adalah langkah-langkahnya:
ClientHelloInilah sebabnya mengatur User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... tidak membantu. User-Agent adalah header tingkat HTTP. Pemindaian fingerprint TLS beroperasi di lapisan yang lebih rendah. Jika User-Agent Anda mengatakan Chrome tetapi fingerprint TLS Anda mengatakan Go, permintaan akan langsung ditandai.
Pemindaian fingerprint TLS telah menjadi praktik standar dalam perlindungan bot perusahaan. Berikut adalah layanan utama yang memeriksa fingerprint TLS:
| Layanan Anti-Bot | Pemeriksaan TLS | Catatan |
|---|---|---|
| Cloudflare Bot Management | Ya | Tantangan "Verifying your browser..." halaman penuh. Memeriksa JA3/JA4 pada setiap permintaan |
| Akamai Bot Manager | Ya | Menggunakan pemindaian fingerprint TLS sebagai salah satu sinyal dalam skoring bot |
| DataDome | Ya | Menganalisis fingerprint TLS bersama dengan sinyal perilaku |
| Banyak lainnya | Berbeda | Pemindaian fingerprint TLS semakin menjadi standar dalam perlindungan bot perusahaan |
CapSolver mendukung penyelesaian tantangan dari banyak layanan ini. Server TLS dalam panduan ini dirancang untuk bekerja bersama dengan alur kerja penyelesaian captcha mana pun di mana permintaan HTTP akhir perlu terlihat seperti lalu lintas browser nyata — baik Anda melewati Tantangan Cloudflare, Akamai, DataDome, atau sistem anti-bot lainnya.
| Persyaratan | Catatan |
|---|---|
| n8n self-hosted | Diperlukan — server TLS harus berjalan di mesin yang sama dengan n8n. n8n Cloud tidak cocok. |
| Go 1.21+ | Harus diinstal di server. Periksa dengan go version. |
| Manajer proses (direkomendasikan) | Manajer proses apa pun (systemd, supervisor, Docker, PM2) untuk menjaga server TLS tetap berjalan setelah restart |
Server TLS adalah server HTTP Go yang ringan yang menerima permintaan di port 7878 dan meneruskannya menggunakan preset Chrome-145 dari httpcloak.
mkdir -p ~/tls-server && cd ~/tls-server
Buat file bernama main.go dengan konten berikut:
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
"github.com/sardanioss/httpcloak/client"
)
type FetchRequest struct {
URL string `json:"url"`
Method string `json:"method"`
Headers map[string]string `json:"headers"`
Proxy string `json:"proxy"`
Body string `json:"body"`
}
type FetchResponse struct {
Status int `json:"status"`
Body string `json:"body"`
Headers map[string][]string `json:"headers"`
}
type ErrorResponse struct {
Error string `json:"error"`
}
func writeError(w http.ResponseWriter, status int, msg string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(ErrorResponse{Error: msg})
}
func fetchHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeError(w, http.StatusMethodNotAllowed, "hanya POST yang diizinkan")
return
}
var req FetchRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "JSON tidak valid: "+err.Error())
return
}
if req.URL == "" {
writeError(w, http.StatusBadRequest, "url diperlukan")
return
}
if req.Method == "" {
req.Method = "GET"
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
c := client.NewClient("chrome-145", client.WithTimeout(60*time.Second))
defer c.Close()
if req.Proxy != "" {
c.SetProxy(req.Proxy)
}
headers := make(map[string][]string, len(req.Headers))
var userAgent string
for k, v := range req.Headers {
lower := strings.ToLower(k)
if lower == "user-agent" {
userAgent = v
} else {
headers[k] = []string{v}
}
}
var bodyReader io.Reader
if req.Body != "" {
bodyReader = strings.NewReader(req.Body)
}
hcReq := &client.Request{
Method: strings.ToUpper(req.Method),
URL: req.URL,
Headers: headers,
Body: bodyReader,
UserAgent: userAgent,
FetchMode: client.FetchModeNavigate,
}
resp, err := c.Do(ctx, hcReq)
if err != nil {
writeError(w, http.StatusBadGateway, "fetch gagal: "+err.Error())
return
}
body, err := resp.Text()
if err != nil {
writeError(w, http.StatusInternalServerError, "baca body gagal: "+err.Error())
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(FetchResponse{
Status: resp.StatusCode,
Body: body,
Headers: resp.Headers,
})
}
func main() {
const port = "7878"
mux := http.NewServeMux()
mux.HandleFunc("/fetch", fetchHandler)
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{"status":"ok"}`)
})
log.Printf("Server TLS (httpcloak chrome-145) mendengarkan di :%s", port)
log.Fatal(http.ListenAndServe(":"+port, mux))
}
go mod init tls-server
go get github.com/sardanioss/httpcloak/client
go build -o main main.go
./main
Server berjalan di latar depan. Untuk menjaga server tetap berjalan di latar belakang, gunakan manajer proses apa pun (systemd, supervisor, Docker, dll.) atau jalankan di sesi screen/tmux.
curl http://localhost:7878/health
Hasil yang diharapkan: {"status":"ok"}
Catatan: Server TLS harus berjalan di mesin yang sama dengan instansi n8n Anda. Alur kerja n8n memanggilnya di
http://localhost:7878/fetch.
Secara default, n8n memblokir node HTTP Request dari memanggil alamat localhost (perlindungan SSRF). Anda perlu menonaktifkan ini agar alur kerja Anda dapat mengakses server TLS di localhost:7878.
Tambahkan variabel lingkungan N8N_BLOCK_ACCESS_TO_LOCALHOST=false dan restart instansi n8n Anda. Cara melakukannya tergantung pada cara Anda menjalankan n8n:
Jika Anda menjalankan n8n secara langsung:
export N8N_BLOCK_ACCESS_TO_LOCALHOST=false
n8n start
Jika Anda menggunakan Docker:
Tambahkan -e N8N_BLOCK_ACCESS_TO_LOCALHOST=false ke perintah docker run Anda, atau tambahkan ke bagian environment dalam docker-compose.yml.
Server TLS menawarkan satu endpoint yang menerima permintaan HTTP apa pun dan meneruskannya dengan fingerprint TLS Chrome.
Endpoint: POST http://localhost:7878/fetch
Badan permintaan (JSON):
{
"url": "https://example.com",
"method": "GET",
"headers": {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
"cookie": "cf_clearance=abc123; session=xyz"
},
"proxy": "http://user:pass@host:port",
"body": ""
}
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
url |
string | Ya | URL target untuk diambil |
method |
string | Tidak | Metode HTTP — defaultnya GET |
headers |
objek | Tidak | Pasangan kunci-nilai header HTTP yang dikirim |
proxy |
string | Tidak | URL proxy dalam format http://user:pass@host:port |
body |
string | Tidak | Isi permintaan (untuk permintaan POST/PUT) |
Respons (JSON):
{
"status": 200,
"body": "<html>...</html>",
"headers": { "content-type": ["text/html"], "..." : ["..."] }
}
Untuk memanggil server TLS dari alur kerja n8n, gunakan Node HTTP Request dengan pengaturan berikut:
| Parameter | Nilai | Deskripsi |
|---|---|---|
| Metode | POST |
Selalu POST ke server TLS |
| URL | http://localhost:7878/fetch |
Endpoint server TLS lokal |
| Tipe Konten | Mentah |
Jangan gunakan JSON — mode JSON n8n mengserialisasi secara salah |
| Tipe Konten Mentah | application/json |
Beri tahu server TLS bahwa badan adalah JSON |
| Badan | ={{ JSON.stringify({ url: "...", method: "GET", headers: {...}, proxy: "..." }) }} |
Permintaan sebenarnya yang akan diteruskan |
Penting: Menggunakan
contentType: "json"denganJSON.stringify()dalam badan menyebabkan n8n menggandakan serialisasi, mengirim{"": ""}alih-alih data Anda. Selalu gunakancontentType: "raw"denganrawContentType: "application/json".
Dalam ekspresi badan node HTTP Request:
={{ JSON.stringify({
url: "https://protected-site.com/data",
method: "GET",
headers: {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"accept-language": "en-US,en;q=0.9"
},
proxy: "http://user:pass@proxy-host:8080"
}) }}
Server TLS akan meneruskan permintaan ini dengan fingerprint TLS Chrome-145, dan target akan melihat koneksi browser Chrome yang asli.
Uji server TLS langsung dari baris perintah:
curl -X POST http://localhost:7878/fetch \
-H "Content-Type: application/json" \
-d '{
"url": "https://tls-check.example.com",
"method": "GET",
"headers": {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
}
}'
Anda dapat memverifikasi fingerprint TLS dengan mengarahkan server ke pemeriksa fingerprint JA3/JA4 — hasilnya harus sesuai dengan browser Chrome nyata, bukan klien Go standar.
Alur kerja ini menciptakan endpoint webhook yang meneruskan setiap permintaan melalui server TLS dengan fingerprint TLS Chrome. Kirim POST dengan url, method, headers, dan proxy opsional — alur kerja meneruskannya ke localhost:7878/fetch dan mengembalikan hasilnya.
Webhook (POST /tls-fetch) → Fetch melalui Server TLS → Balas ke Webhook
Salin JSON berikut dan impor ke n8n melalui Menu → Impor dari JSON.
{
"name": "TLS Fetch — Chrome Fingerprint Proxy",
"nodes": [
{
"parameters": {
"content": "## TLS Fetch — Chrome Fingerprint Proxy\n\n**Untuk siapa:** Pengembang yang membutuhkan permintaan HTTP dengan fingerprint TLS browser yang otentik.\n\n**Apa yang dilakukan:** Memproksikan permintaan HTTP melalui server TLS Go (httpcloak) yang meniru fingerprint TLS Chrome, melewati deteksi bot.\n\n**Cara kerjanya:**\n1. Webhook menerima URL target dan detail permintaan\n2. Permintaan diteruskan ke server TLS lokal dengan fingerprint Chrome\n3. Respons dikembalikan ke pemanggil\n\n**Pengaturan:**\n1. Pastikan server TLS (httpcloak) berjalan di port 7878\n2. Aktifkan alur kerja\n3. Kirim POST ke URL webhook dengan detail permintaan Anda",
"height": 494,
"width": 460,
"color": 1
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-720,
-300
],
"id": "sticky-blog-main-1773678228122-1",
"name": "Catatan Menempel"
},
{
"parameters": {
"httpMethod": "POST",
"path": "tls-fetch",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-200,
0
],
"id": "tls00001-0001-0001-0001-000000000001",
"name": "Menerima Permintaan Solver",
"webhookId": "tls00001-aaaa-bbbb-cccc-000000000001"
},
{
"parameters": {
"method": "POST",
"url": "http://localhost:7878/fetch",
"sendBody": true,
"contentType": "raw",
"rawContentType": "application/json",
"body": "={{ JSON.stringify($json.body) }}",
"options": {
"timeout": 60000
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
100,
0
],
"id": "tls00001-0001-0001-0001-000000000002",
"name": "Ambil melalui Server TLS"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
400,
0
],
"id": "tls00001-0001-0001-0001-000000000003",
"name": "Balas Webhook"
}
],
"connections": {
"Menerima Permintaan Solver": {
"main": [
[
{
"node": "Ambil melalui Server TLS",
"type": "main",
"index": 0
}
]
]
},
"Ambil melalui Server TLS": {
"main": [
[
{
"node": "Balas Webhook",
"t
Bangun API solver eCAPTCHA v2/v3 menggunakan CapSolver dan n8n. Pelajari cara mengotomatisasi penyelesaian token, mengirimkannya ke website, dan mengekstrak data yang dilindungi tanpa coding.

Buat API untuk menyelesaikan Cloudflare Turnstile menggunakan CapSolver dan n8n. Pelajari cara mengotomatisasi proses pengambilan token, mengirimkannya ke situs web, dan mengekstrak data yang dilindungi tanpa perlu coding.
