ChatGPT sẽ không cho phép bạn nhập cho đến khi Cloudflare đọc React state của bạn
ChatGPT won't let you type until Cloudflare reads your React state
Các nhà phát triển Việt Nam nên biết rằng Cloudflare Turnstile, dịch vụ mà ChatGPT đang sử dụng để chống bot, thực hiện kỹ thuật **browser fingerprinting** nâng cao hơn nhiều so với các phương pháp phát hiện bot truyền thống. Cụ thể, nó kiểm tra khả năng của trình duyệt trong việc **render** một ứng dụng **React** cụ thể, bằng cách xem xét tới 55 thuộc tính thuộc về **browser**, **network** và **application state**. Điều này cho thấy các chiến lược chống bot hiện nay đang phát triển mạnh mẽ, không chỉ dừng lại ở việc nhận diện hành vi bất thường mà còn có thể xác minh trực tiếp quá trình render ứng dụng và trạng thái nội bộ của nó. Các **developers** cần lưu ý điều này để điều chỉnh các chiến lược **bot mitigation** của mình cho phù hợp với xu hướng mới.
Mỗi tin nhắn ChatGPT sẽ kích hoạt chương trình Cloudflare Turnstile chạy âm thầm trong trình duyệt của bạn. Tôi đã giải mã 377 chương trình này khỏi lưu lượng truy cập mạng và tìm thấy thứ gì đó vượt xa khả năng lấy dấu vân tay của trình duyệt tiêu chuẩn. Chương trình kiểm tra 55 thuộc tính trải rộng trên ba lớp: trình duyệt của bạn (GPU, màn hình, phông chữ), mạng Cloudflare (thành phố, IP của bạn, khu vực của bạn từ các tiêu đề cạnh) và chính ứng dụng ChatGPT React (__reactRouterContext, LoaderData, clientBootstrap). Cửa quay không
Mỗi tin nhắn ChatGPT sẽ kích hoạt chương trình Cloudflare Turnstile chạy âm thầm trong trình duyệt của bạn. Tôi đã giải mã 377 chương trình trong số này khỏi lưu lượng truy cập mạng và tìm thấy thứ gì đó vượt xa việc lấy dấu vân tay của trình duyệt tiêu chuẩn.
Chương trình này kiểm tra 55 thuộc tính trải rộng trên ba lớp: trình duyệt của bạn (GPU, màn hình, phông chữ), mạng Cloudflare (thành phố, IP của bạn, khu vực của bạn từ các tiêu đề cạnh) và chính ứng dụng ChatGPT React (__reactRouterContext, loaderData, clientBootstrap). Turnstile không chỉ xác minh rằng bạn đang chạy một trình duyệt thực sự. Nó xác minh rằng bạn đang chạy một trình duyệt thực đã khởi động hoàn toàn một ứng dụng React cụ thể.
Một bot giả mạo dấu vân tay của trình duyệt nhưng không hiển thị ChatGPT SPA thực tế sẽ không thành công.
Mã hóa được cho là để ẩn thông tin này
Mã byte Turnstile đã được mã hóa. Máy chủ gửi một trường có tên turnstile.dx trong phản hồi chuẩn bị: 28.000 ký tự base64 thay đổi theo mọi yêu cầu.
Lớp bên ngoài là XOR với mã thông báo p từ yêu cầu chuẩn bị. Cả hai đều di chuyển trong cùng một trao đổi HTTP, do đó việc giải mã nó rất đơn giản:
outer = json.loads(bytes(
base64decode(dx)[i] ^ p_token[i % len(p_token)]
cho tôi trong phạm vi(len(base64decode(dx)))
))
# → 89 lệnh VM
Bên trong 89 hướng dẫn đó có một blob được mã hóa 19KB chứa chương trình lấy dấu vân tay thực tế. Blob bên trong này sử dụng một khóa XOR khác không phải là mã thông báo p.
Ban đầu, tôi cho rằng khóa này được lấy từ performance.now() và thực sự là tạm thời. Sau đó, tôi xem xét mã byte cẩn thận hơn và tìm thấy khóa nằm trong hướng dẫn:
[41.02, 0.3, 22.58, 12.96, 97.35]
Đối số cuối cùng, 97,35, là khóa XOR. Một chữ nổi do máy chủ tạo ra, được nhúng vào mã byte mà nó gửi tới trình duyệt. Tôi đã xác minh điều này qua 50 yêu cầu. Mỗi lần, float từ lệnh sẽ giải mã blob bên trong thành JSON hợp lệ. 50 trên 50.
Chuỗi giải mã đầy đủ không yêu cầu gì ngoài yêu cầu và phản hồi HTTP:
1. Đọc p từ yêu cầu chuẩn bị
2. Đọc Turnstile.dx từ phản hồi chuẩn bị
3. XOR(base64decode(dx), p) → mã byte bên ngoài
4. Tìm lệnh 5 đối số sau blob 19KB → đối số cuối cùng là khóa
5. XOR(base64decode(blob), str(key)) → chương trình bên trong (lệnh 417-580 VM)
Khóa nằm trong tải trọng.
Chương trình được giải mã kiểm tra những gì
Mỗi chương trình bên trong sử dụng một VM tùy chỉnh với 28 mã hoạt động (ADD, XOR, CALL, BTOA, RESOLVE, BIND_METHOD, JSON_STRINGIFY, v.v.) và các địa chỉ thanh ghi float ngẫu nhiên thay đổi theo yêu cầu. Tôi đã ánh xạ các mã hoạt động từ nguồn SDK (sdk.js, 1.411 dòng, đã được giải mã).
Chương trình thu thập 55 thuộc tính. Không có biến thể trên 377 mẫu. Tất cả 55, mọi lúc, được tổ chức thành ba lớp:
Lớp 1: Dấu vân tay của trình duyệt
WebGL (8 thuộc tính): UNMASKED_VENDOR_WEBGL, UNMASKED_RENDERER_WEBGL, WEBGL_debug_renderer_info, getExtension, getParameter, getContext, canvas, webgl
Màn hình (8): colorDepth, pixelDepth, width, height, availWidth, availHeight, availLeft, availTop
Phần cứng (5): hardwareConcurrency, deviceMemory, maxTouchPoints, nền tảng, nhà cung cấp
Đo lường phông chữ (4): fontFamily, fontSize, getBoundingClientRect, innerText. Tạo div ẩn, đặt phông chữ, đo kích thước văn bản được hiển thị, xóa phần tử.
Thăm dò DOM (8): createElement, appendChild, removeChild, div, style, position, visibility, ariaHidden
Bộ nhớ (5): bộ nhớ, hạn ngạch , ước tính, setItem, mức sử dụng. Đồng thời ghi dấu vân tay vào localStorage dưới khóa 6f376b6560133c2c để duy trì liên tục trong các lần tải trang.
Lớp 2: Mạng Cloudflare
Tiêu đề cạnh (5): cfIpCity, cfIpLatitude, cfIpLongitude, cfConnectingIp, userRegion
Chúng được đưa vào phía máy chủ bởi cạnh của Cloudflare. Chúng chỉ tồn tại nếu yêu cầu được chuyển qua mạng của Cloudflare. Một bot thực hiện yêu cầu trực tiếp đến máy chủ gốc hoặc chạy phía sau proxy không phải của Cloudflare sẽ tạo ra các giá trị bị thiếu hoặc không nhất quán.
Lớp 3: Trạng thái ứng dụng
Nội bộ phản ứng (3): __reactRouterContext, loaderData, clientBootstrap
Đây là phần quan trọng. __reactRouterContext là cấu trúc dữ liệu nội bộ mà React Router v6+ gắn vào DOM. loaderData chứa kết quả của trình tải tuyến đường. clientBootstrap dành riêng cho quá trình hydrat hóa SSR của ChatGPT.
Các thuộc tính này chỉ tồn tại nếu ứng dụng ChatGPT React đã được hiển thị và ngậm nước hoàn toàn. Trình duyệt không có giao diện người dùng tải HTML nhưng không thực thi gói JavaScript sẽ không có chúng. Một khung bot loại bỏ các API trình duyệt nhưng không thực sự chạy React sẽ không có chúng.
Đây là tính năng phát hiện bot ở lớp ứng dụng chứ không phải lớp trình duyệt.
Lối ra: Cách tạo mã thông báo
Sau khi thu thập tất cả 55 thuộc tính, chương trình sẽ chạm vào một blob được mã hóa 116 byte giải mã thành 4 hướng dẫn cuối cùng:
[
[96,05, 3,99, 3,99], // JSON.stringify(dấu vân tay)
[22,58, 46,15, 57,34], // lưu trữ
[33,34, 3,99, 74,43], // XOR(json, key)
[1,51, 56,88, 3,99] // GIẢI QUYẾT → trở thành mã thông báo
]
Dấu vân tay là JSON.stringify'd, XOR'd và được phân giải lại cho cấp độ gốc. Kết quả là tiêu đề OpenAI-Sentinel-Turnstile-Token được gửi cùng với mọi yêu cầu trò chuyện.
What Else Sentinel Runs
Turnstile là một trong ba thử thách. Hai phần còn lại:
Signal Orchestrator (271 hướng dẫn): Cài đặt trình xử lý sự kiện cho keydown, pointermove, nhấp, cuộn, dán và bánh xe. Giám sát 36 thuộc tính window.__oai_so_* theo dõi thời gian gõ phím, tốc độ chuột, kiểu cuộn, thời gian rảnh và sự kiện dán. Lớp sinh trắc học hành vi chạy bên dưới dấu vân tay.
Bằng chứng công việc (dấu vân tay 25 trường + mã băm SHA-256): Độ khó là ngẫu nhiên thống nhất (400K-500K), 72% giải quyết dưới 5 mili giây. Bao gồm 7 cờ phát hiện nhị phân (ai, createPRNG, cache, solana, dump, InstallTrigger, data), tất cả đều bằng 0 trên 100% trong số 100 mẫu. PoW tăng thêm chi phí điện toán nhưng không phải là biện pháp phòng vệ thực sự.
Ai có thể giải mã mã thông báo
Khóa XOR cho chương trình bên trong là một float do máy chủ tạo được nhúng trong mã byte. Bất cứ ai tạo turnstile.dx đều biết khóa. Ranh giới về quyền riêng tư giữa người dùng và nhà điều hành hệ thống là một quyết định về chính sách, không phải là quyết định về mật mã.
Việc che giấu phục vụ các mục đích hoạt động thực sự: nó ẩn danh sách kiểm tra dấu vân tay khỏi phân tích tĩnh, ngăn nhà điều hành trang web (OpenAI) đọc các giá trị dấu vân tay thô mà không cần thiết kế ngược mã byte, làm cho mỗi mã thông báo trở thành duy nhất để ngăn chặn việc phát lại và cho phép Cloudflare thay đổi những gì chương trình kiểm tra mà không cần có ai để ý không.
Nhưng "mã hóa" là XOR với khóa nằm trong cùng một luồng dữ liệu. Nó ngăn cản việc kiểm tra thông thường. Nó không ngăn cản việc phân tích.
Những con số
<đầu>Phương pháp luận
Không có hệ thống nào được truy cập mà không được phép. Không có dữ liệu người dùng cá nhân được tiết lộ. Tất cả lưu lượng truy cập đã được quan sát từ những người tham gia đồng ý. SDK Sentinel đã được cải tiến và giải mã thủ công. Tất cả quá trình giải mã được thực hiện ngoại tuyến bằng Python.
Tác giả: alberto-m