curl-impersonate: bản build curl đặc biệt có thể giả lập các trình duyệt chính
(github.com/lwthiker)- curl-impersonate là một bản build curl được chỉnh sửa để thực hiện TLS và HTTP handshake trông giống Chrome, Edge, Safari, Firefox; có thể dùng như công cụ CLI và thư viện thay thế
libcurl - Client Hello và thiết lập HTTP/2 của các HTTP client và thư viện thông thường khác rất nhiều so với trình duyệt thật, nên một số dịch vụ web nhận diện client qua TLS/HTTP handshake và cung cấp nội dung khác nhau
- Cách triển khai gồm dùng NSS cho Firefox, BoringSSL cho họ Chrome, thay đổi TLS extension, tùy chọn SSL, thiết lập HTTP/2, và áp dụng các flag không mặc định như
--ciphers,--curves, header - Các mục tiêu được hỗ trợ gồm Chrome 99~116, Android Chrome 99, Edge 99·101, Firefox 91 ESR~117, Safari 15.3·15.5; mỗi mục tiêu có wrapper script và target name riêng
- Trên dòng lệnh, chạy
curl_chrome116; khi tích hợp thư viện, có thể áp dụng vào ứng dụng đang dùnglibcurlhiện có bằngcurl_easy_impersonate()hoặcLD_PRELOADvàCURL_IMPERSONATEtrên Linux
Vấn đề mà curl-impersonate giải quyết
- curl-impersonate là dự án build đặc biệt curl để có thể giả lập 4 trình duyệt lớn: Chrome, Edge, Safari, Firefox
- Có thể thực hiện TLS và HTTP handshake giống hệt trình duyệt thật
- Có hai cách sử dụng
- Công cụ dòng lệnh tương tự curl thông thường
- Thư viện có thể tích hợp thay cho
libcurlhiện có
Vì sao cần nó
- Khi HTTP client kết nối tới website TLS, trước tiên nó thực hiện TLS handshake
- Thông điệp đầu tiên của TLS handshake là Client Hello, và Client Hello do hầu hết HTTP client và thư viện tạo ra khác rất nhiều so với trình duyệt thật
- Nếu server dùng HTTP/2, ngoài TLS handshake còn thực hiện HTTP/2 handshake, trong đó nhiều thiết lập được trao đổi
- Thiết lập HTTP/2 của hầu hết HTTP client và thư viện cũng khác với trình duyệt thật
- Một số dịch vụ web tận dụng những khác biệt này để nhận diện client đang kết nối và cung cấp nội dung khác nhau theo từng client
- Cách này được gọi là TLS fingerprinting và HTTP/2 fingerprinting
- README cho biết việc sử dụng rộng rãi cách này đã khiến web kém mở hơn, kém riêng tư hơn và bị giới hạn hơn đối với một số web client nhất định
Cách hoạt động
curlđược patch đáng kể để trông giống trình duyệt- Các thay đổi chính như sau
- Phiên bản Firefox biên dịch curl với NSS, thư viện TLS mà Firefox sử dụng, thay vì OpenSSL
- Phiên bản Chrome được biên dịch với BoringSSL, thư viện TLS của Google
- Thay đổi cách curl thiết lập nhiều TLS extension và tùy chọn SSL
- Bổ sung hỗ trợ các TLS extension mới
- Thay đổi các thiết lập dùng cho kết nối HTTP/2
- Chạy curl với các flag không mặc định như
--ciphers,--curves, một số header-H
- Kết quả là, nhìn từ góc độ mạng, curl trông giống hệt trình duyệt thật
- Phần giải thích kỹ thuật đầy đủ có tại part a, part b
Trình duyệt được hỗ trợ và tên mục tiêu
- Danh sách trình duyệt được hỗ trợ cũng có trong
browsers.json - Các mục tiêu hỗ trợ họ Chrome
- Chrome 99, 100, 101, 104, 107, 110, 116 trên Windows 10
- Chrome 99 trên Android 12
- Edge 99, 101 trên Windows 10
- Safari 15.3 trên MacOS Big Sur
- Safari 15.5 trên MacOS Monterey
- Các mục tiêu hỗ trợ Firefox
- Firefox 91 ESR, 95, 98, 100, 102, 109, 117 trên Windows 10
- Mỗi mục tiêu được hỗ trợ có target name và wrapper script
- Ví dụ: target
chrome116chạy bằng wrapper scriptcurl_chrome116 - Ví dụ: target
ff117chạy bằng wrapper scriptcurl_ff117
- Ví dụ: target
Cách dùng cơ bản
- Với mỗi trình duyệt được hỗ trợ đều có wrapper script chạy
curl-impersonatekèm các header và flag cần thiết - Ví dụ chạy
curl_chrome116 https://www.wikipedia.org - Nếu thêm flag dòng lệnh, chúng sẽ được chuyển cho curl
- Một số flag có thể làm thay đổi TLS signature của curl và bị phát hiện
- Wrapper script dùng một tập HTTP header mặc định
- Nếu muốn thay đổi header, có thể chỉnh wrapper script theo mục đích
- Các tùy chọn khác nằm trong phần sử dụng nâng cao với
libcurl-impersonatedưới dạng thư viện
Cài đặt và cách phân phối
- Vì lý do kỹ thuật,
curl-impersonatecó hai phiên bản- Phiên bản chrome: dùng để giả lập Chrome, Edge, Safari
- Phiên bản firefox: dùng để giả lập Firefox
- Binary biên dịch sẵn cho Linux và macOS Intel có trên GitHub releases
- Trước khi dùng binary biên dịch sẵn, cần cài NSS và chứng chỉ CA
- Ubuntu:
sudo apt install libnss3 nss-plugin-pem ca-certificates - Red Hat/Fedora/CentOS:
yum install nss nss-pem ca-certificates - Archlinux:
pacman -S nss ca-certificates - macOS:
brew install nss ca-certificates
- Ubuntu:
- Hệ thống cũng cần zlib
- zlib hầu như luôn có, nhưng có thể không có trên một số hệ thống tối giản
- Binary Linux biên dịch sẵn được build cho hệ thống Ubuntu
- Nếu gặp lỗi xác minh chứng chỉ trên bản phân phối khác, có thể cần cho curl biết vị trí chứng chỉ CA
curl_chrome116 https://www.wikipedia.org --cacert /etc/ssl/certs/ca-bundle.crt - Để build từ source, tham khảo INSTALL.md
Docker và package
- Docker image dựa trên Alpine Linux và Debian có trên Docker Hub
- Docker image bao gồm binary và toàn bộ wrapper script
- Ví dụ
# Firefox version, Alpine Linux docker pull lwthiker/curl-impersonate:0.6-ff docker run --rm lwthiker/curl-impersonate:0.6-ff curl_ff109 https://www.wikipedia.org # Chrome version, Alpine Linux docker pull lwthiker/curl-impersonate:0.6-chrome docker run --rm lwthiker/curl-impersonate:0.6-chrome curl_chrome110 https://www.wikipedia.org - Người dùng Archlinux có thể dùng package AUR
- Package biên dịch sẵn: curl-impersonate-bin, libcurl-impersonate-bin
- Package build từ source: curl-impersonate-chrome, curl-impersonate-firefox
- Homebrew formula không chính thức cho Mac chỉ được cung cấp cho Chrome
brew tap shakacode/brew brew install curl-impersonate
Sử dụng nâng cao libcurl-impersonate
libcurl-impersonate.solà libcurl được biên dịch với các thay đổi giốngcurl-impersonatedòng lệnh- Có thêm hàm API
CURLcode curl_easy_impersonate(struct Curl_easy *data, const char * target, int default_headers); - Khi gọi với target name như
chrome116, nó sẽ thiết lập nội bộ các tùy chọn và header mà wrapper script từng thiết lập - Nếu
default_headerslà 0, danh sách HTTP header tích hợp sẽ không được thiết lập- Người dùng phải tự cung cấp header bằng tùy chọn libcurl thông thường
CURLOPT_HTTPHEADER
- Người dùng phải tự cung cấp header bằng tùy chọn libcurl thông thường
curl_easy_impersonate()thiết lập nhiều tùy chọn libcurlCURLOPT_HTTP_VERSIONCURLOPT_SSLVERSION,CURLOPT_SSL_CIPHER_LIST,CURLOPT_SSL_EC_CURVES,CURLOPT_SSL_ENABLE_NPN,CURLOPT_SSL_ENABLE_ALPN- Tùy chọn không chuẩn dành cho dự án:
CURLOPT_HTTPBASEHEADER - Tùy chọn HTTP/2 không chuẩn dành cho dự án:
CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER,CURLOPT_HTTP2_NO_SERVER_PUSH - Tùy chọn TLS không chuẩn dành cho dự án:
CURLOPT_SSL_ENABLE_ALPS,CURLOPT_SSL_SIG_HASH_ALGS,CURLOPT_SSL_CERT_COMPRESSION,CURLOPT_SSL_ENABLE_TICKET - Tùy chọn TLS không chuẩn dành cho dự án:
CURLOPT_SSL_PERMUTE_EXTENSIONS
- Sau đó, nếu gọi một trong các tùy chọn trên bằng
curl_easy_setopt(), giá trị docurl_easy_impersonate()thiết lập sẽ bị ghi đè
Áp dụng vào ứng dụng libcurl hiện có
- Nếu ứng dụng đã dùng
libcurl, trên Linux có thể thay thế thư viện hiện có lúc runtime bằngLD_PRELOAD - Thiết lập biến môi trường
CURL_IMPERSONATEđể áp dụng giả lập tự độngLD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 my_app CURL_IMPERSONATEcó hai tác dụng- Khi một curl handle mới được tạo bằng
curl_easy_init(),curl_easy_impersonate()được gọi tự động - Sau
curl_easy_reset(),curl_easy_impersonate()cũng được gọi tự động
- Khi một curl handle mới được tạo bằng
- Nếu cần kiểm soát HTTP header chính xác, hãy tắt danh sách header tích hợp bằng
CURL_IMPERSONATE_HEADERS=novà tự thiết lậpLD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 CURL_IMPERSONATE_HEADERS=no my_app - Cách dùng
LD_PRELOADkhông hoạt động với chính curl- Vì công cụ curl ghi đè thiết lập TLS
- Với curl, phải dùng wrapper script
Cấu trúc repository và đóng góp
- Repository có hai thư mục chính
- Ví dụ thư mục Firefox gồm các file sau
- Dockerfile: dùng để build
curl-impersonatecùng toàn bộ dependency - curl_ff91esr, curl_ff95, curl_ff98: wrapper script chạy với flag đúng
- curl-impersonate.patch: patch chính giúp curl dùng TLS extension giống Firefox, đồng thời được biên dịch tĩnh với libnghttp2 và libnss
- Dockerfile: dùng để build
- tests/signatures là cơ sở dữ liệu YAML về signature của các trình duyệt đã biết có thể giả lập
- Patch curl thực tế được duy trì trong một repository riêng fork từ upstream curl
- Thay đổi cho Firefox nằm ở nhánh impersonate-firefox
- Thay đổi cho Chrome nằm ở nhánh impersonate-chrome
1 bình luận
Ý kiến trên Hacker News
Có một fork được bảo trì tích cực với khá nhiều cải tiến so với bản gốc: https://github.com/lexiforest/curl-impersonate
Cũng có binding cho người dùng Python: https://github.com/lexiforest/curl_cffi
Trớ trêu là yêu cầu đó có lẽ còn ít gây tải cho máy chủ hơn một trình duyệt đã được chứng nhận, và tôi tự hỏi liệu đây có phải là kiểu phản địa đàng mà người ta đã cảnh báo từ thập niên 90 không. Tôi tò mò liệu ở đây có ai dám nêu tên công ty đã tạo ra tình huống này trong khi vẫn định vị mình như một người đóng góp tốt đẹp cho cộng đồng mã nguồn mở/hacker hay không
Hy vọng Ladybird sẽ có thêm sức hút trong tương lai. Hiện tại phần networking dùng cURL chính thức, nhưng cách này có thể gặp trở ngại
Ví dụ, theo tôi biết cURL vẫn có một số hạn chế và không xử lý được WebSocket trên h2. Mặt khác, nếu có một engine trình duyệt đang phát triển, lưu lượng hợp lệ cũng sẽ có fingerprint giống cURL mặc định, và có thể con đường lấy fingerprint này sẽ biến mất
Đây cũng là một phép thử tốt để xem cURL còn thiếu tính năng nào theo quy trình làm việc của trình duyệt thực tế
Trong vài tháng qua, mức độ lấy fingerprint và “lạm dụng” hành vi do implementation định nghĩa đã tăng mạnh, và có lẽ là một nỗ lực nhằm bóp chết các engine trình duyệt khác. Những kẻ thống trị hiện tại hoàn toàn không thích cạnh tranh
Phía bên kia cố đóng gói chuyện này thành “DDoS của bot AI”, nhưng tôi tự hỏi trong số đó có bao nhiêu phần là do chính họ tạo ra
Tôi thích curl này, nhưng lo rằng nếu một thành phần nào đó phải đóng vai trò đánh lừa để “bắt kịp”, nó sẽ tích lũy một gánh nặng “tương thích” khó bảo trì
Lý tưởng nhất là chỉ cần nói “xin chào, tôi là curl, cho tôi vào”
Tất nhiên vấn đề nằm ở các máy chủ khắt khe về quy định trang phục, và vấn đề đó lại xuất phát từ những kẻ lừa đảo cải trang để đi vào, nên nó vòng vo như chuyện con gà và quả trứng
[0] https://cybershow.uk/episodes.php?id=39
Ngoài ra, việc nó được thiết kế lại bằng C++, thứ có thể chứng minh là không an toàn, cũng là một rủi ro bảo mật lớn
Không biết họ có đặt cả
IP_TTLđể khớp với giá trị TTL của nền tảng mà họ muốn giả mạo không?Nếu không, ở tầng IP cũng có thể lấy fingerprint ở một mức độ nào đó. Nếu giá trị TTL ở tầng IP nhỏ hơn 64, thì rõ ràng nó không chạy trên Windows hiện đại, hoặc là Windows hiện đại đã đổi TTL mặc định. Vì TTL mặc định của gói tin trên Windows hiện đại bắt đầu từ 128, còn hầu hết nền tảng khác bắt đầu từ 64
Các nền tảng khác cũng giao tiếp Internet không có vấn đề gì, nên gói IP đến từ Windows hiện đại sẽ luôn được phía từ xa nhìn thấy với TTL từ 64 trở lên, có lẽ là lớn hơn 64 một chút. Tuy nhiên, fingerprint ở tầng IP thì khó, nhưng không phải bất khả thi
https://en.wikipedia.org/wiki/TCP/IP_stack_fingerprinting
Khoan đã, nếu TLS handshake trông khác nhau, chẳng phải có thể lọc ở mức nginx những lưu lượng tự nhận là trình duyệt web nhưng thực ra là script Python/PHP sao?
Ví dụ trường hợp dùng user agent của Chrome nhưng không phải trình duyệt thật. Phần lớn lưu lượng bot độc hại chắc thuộc loại này, nên nếu chặn được luôn thì tốt
Cách hoạt động được mô tả chi tiết tại https://github.com/FoxIO-LLC/ja4/blob/main/technical_details..., và cũng có module Nginx: https://github.com/FoxIO-LLC/ja4-nginx-module
Nếu hiện không thực sự bị tấn công thì không nên dùng danh sách cho phép fingerprint TLS
Đây là một công cụ tuyệt vời, nhưng việc client có phải là trình duyệt hay không lẽ ra không nên quan trọng. Thật chua chát khi ngoài đời lại cần đến những công cụ như thế này
Tôi thêm một tiện ích đổi user agent vào Chrome, đổi sang IE rồi thử lại thì chạy được, và mọi chức năng của trang cũng vẫn ổn. Vì thế vừa chua chát vừa bực bội. Có lẽ cơ quan chính phủ đó đã làm website từ 25 năm trước rồi sau đó không cập nhật nữa
Kiểu gatekeeping này cũng khiến tôi thấy chua chát. Theo tôi hiểu, các trình duyệt tùy biến tự làm hoặc user agent tự tạo sẽ tuyệt đối không hoạt động trên các trang kiểu Cloudflare cho đến khi chúng có đủ tầm ảnh hưởng, tiền bạc, số lượng người dùng hoặc thứ tương tự để thuyết phục họ
Công cụ này khá hữu ích trong công việc red team khi kết hợp các script bash nhỏ với GNU parallel
Nó hữu dụng khi lập bản đồ các endpoint HTTPS trong một dải địa chỉ được chỉ định theo phạm vi, vốn vì nhiều lý do chỉ phản hồi với trình duyệt đúng nghĩa hoặc chỉ phản hồi khi cấu hình SNI khớp. Các tùy chọn curl thông thường như
-Hđể giả mạo header cũng vẫn dùng được nguyên trạngBài Show HN lúc đó: https://news.ycombinator.com/item?id=30378562
Mỗi khi những thứ như thế này xuất hiện ở đây, tôi luôn có cảm giác lẫn lộn. Một mặt, thật tốt khi thấy giữa mọi người vẫn còn chút tinh thần phản kháng và tính độc lập
Mặt khác, giống như các dự án khác bị coi là “tự do thì không ổn định”, nếu thu hút sự chú ý không mong muốn, tình hình có thể trở nên tệ hơn với những người đang phụ thuộc vào nó. Viết trình duyệt là việc khó, và những thế lực đã có vị thế tiếp tục khiến nó khó hơn nữa
Tôi không xem đây là vấn đề về tinh thần phản kháng. Việc phần mềm có thể bị nhận dạng bằng dấu vân tay làm xói mòn quyền riêng tư và sự đa dạng phần mềm
Tôi hơi nhớ thời đơn giản khi website nếu thấy bot ổn thì cho phép, còn nếu không thích thì chặn user agent
Nếu chỉ có 3 bản vá và một shell wrapper thì Daniel hẳn có thể bắt tay vào code. Cá nhân tôi nghĩ thứ này nhất thiết nên được đưa vào curl mainline