CAPSOLVER
Blog
Cara Menyelesaikan Fingerprinting TLS di n8n dengan CapSolver

Cara Menyelesaikan Fingerprinting TLS di n8n dengan CapSolver

Logo of CapSolver

Emma Foster

Machine Learning Engineer

18-Mar-2026

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.


Apa itu Pemindaian Fingerprint TLS?

Setiap kali klien terhubung ke situs web melalui HTTPS, ia memulai handshake TLS dengan mengirimkan pesan ClientHello. Pesan ini berisi:

  • Suite enkripsi โ€” algoritma enkripsi yang didukung klien, dan urutannya
  • Ekstensi TLS โ€” fitur seperti SNI, ALPN, grup yang didukung, algoritma tanda tangan
  • Kurva eliptik dan format titik โ€” parameter kriptografi
  • Versi TLS โ€” versi TLS maksimum yang didukung

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.


Mengapa Klien HTTP Standar Gagal

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:

  1. Alur kerja n8n Anda mengirimkan permintaan HTTP ke situs web yang dilindungi
  2. Handshake TLS dimulai โ€” klien Anda mengirimkan ClientHello
  3. Layanan anti-bot mencatat fingerprint JA3/JA4 dari handshake
  4. Fingerprint cocok dengan Go/Python/Node.js โ€” bukan Chrome atau Firefox
  5. Permintaan diblokir, diperiksa, atau diberi halaman palsu โ€” sebelum header Anda bahkan dievaluasi

Inilah 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.


Siapa yang Menggunakan Pemindaian Fingerprint TLS?

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.


Prasyarat

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

Langkah 1 โ€” Bangun Server TLS

Server TLS adalah server HTTP Go yang ringan yang menerima permintaan di port 7878 dan meneruskannya menggunakan preset Chrome-145 dari httpcloak.

Buat file sumber

bash Copy
mkdir -p ~/tls-server && cd ~/tls-server

Buat file bernama main.go dengan konten berikut:

go Copy
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))
}

Inisialisasi dan bangun

bash Copy
go mod init tls-server
go get github.com/sardanioss/httpcloak/client
go build -o main main.go

Jalankan server

bash Copy
./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.

Verifikasi server berjalan (di terminal baru)

bash Copy
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.


Langkah 2 โ€” Izinkan n8n Memanggil Lokalhost

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:

bash Copy
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.


Langkah 3 โ€” Menggunakan Server TLS dari n8n

Server TLS menawarkan satu endpoint yang menerima permintaan HTTP apa pun dan meneruskannya dengan fingerprint TLS Chrome.

Referensi API

Endpoint: POST http://localhost:7878/fetch

Badan permintaan (JSON):

json Copy
{
  "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):

json Copy
{
  "status": 200,
  "body": "<html>...</html>",
  "headers": { "content-type": ["text/html"], "..." : ["..."] }
}

Mengatur Node HTTP Request n8n

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" dengan JSON.stringify() dalam badan menyebabkan n8n menggandakan serialisasi, mengirim {"": ""} alih-alih data Anda. Selalu gunakan contentType: "raw" dengan rawContentType: "application/json".

Contoh: Mengambil Halaman yang Dilindungi

Dalam ekspresi badan node HTTP Request:

javascript Copy
={{ 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

Uji server TLS langsung dari baris perintah:

bash Copy
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.


Impor Alur Kerja Ini

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.

Copy
Webhook (POST /tls-fetch) โ†’ Fetch melalui Server TLS โ†’ Balas ke Webhook

Salin JSON berikut dan impor ke n8n melalui Menu โ†’ Impor dari JSON.

Klik untuk perluas JSON alur kerja
json Copy
{
  "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

Pernyataan Kepatuhan: Informasi yang diberikan di blog ini hanya untuk tujuan informasi. CapSolver berkomitmen untuk mematuhi semua hukum dan peraturan yang berlaku. Penggunaan jaringan CapSolver untuk kegiatan ilegal, penipuan, atau penyalahgunaan sangat dilarang dan akan diselidiki. Solusi penyelesaian captcha kami meningkatkan pengalaman pengguna sambil memastikan kepatuhan 100% dalam membantu menyelesaikan kesulitan captcha selama pengambilan data publik. Kami mendorong penggunaan layanan kami secara bertanggung jawab. Untuk informasi lebih lanjut, silakan kunjungi Syarat Layanan dan Kebijakan Privasi.

Lebih lanjut