3 điểm bởi GN⁺ 2025-04-04 | 1 bình luận | Chia sẻ qua WhatsApp
  • 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ùng libcurl hiện có bằng curl_easy_impersonate() hoặc LD_PRELOADCURL_IMPERSONATE trê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 libcurl hiệ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 fingerprintingHTTP/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 chrome116 chạy bằng wrapper script curl_chrome116
    • Ví dụ: target ff117 chạy bằng wrapper script curl_ff117

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-impersonate kè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-impersonate dưới dạng thư viện

Cài đặt và cách phân phối

  • Vì lý do kỹ thuật, curl-impersonate có 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
  • 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
  • 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.solibcurl được biên dịch với các thay đổi giống curl-impersonate dò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_headers là 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
  • curl_easy_impersonate() thiết lập nhiều tùy chọn libcurl
    • CURLOPT_HTTP_VERSION
    • CURLOPT_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ị do curl_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ằng LD_PRELOAD
  • Thiết lập biến môi trường CURL_IMPERSONATE để áp dụng giả lập tự động
    LD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 my_app
    
  • CURL_IMPERSONATE có 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
  • 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=no và tự thiết lập
    LD_PRELOAD=/path/to/libcurl-impersonate.so CURL_IMPERSONATE=chrome116 CURL_IMPERSONATE_HEADERS=no my_app
    
  • Cách dùng LD_PRELOAD khô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
    • chrome: script và patch để build phiên bản Chrome của curl-impersonate
    • firefox: script và patch để build phiên bản Firefox của curl-impersonate
  • Ví dụ thư mục Firefox gồm các file sau
  • 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

1 bình luận

 
GN⁺ 2025-04-04
Ý 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

    • Việc một chương trình “làm cho curl trông giống trình duyệt” được tài trợ bởi một dịch vụ vượt qua phát hiện bot thì theo một nghĩa nào đó cũng là điều tự nhiên
    • Cũng có một module tích hợp hoàn toàn thứ này với thư viện requests của Python: https://github.com/el1s7/curl-adapter
    • Thật kỳ lạ khi để tạo một yêu cầu đơn giản trông giống một trong ba trình duyệt web lớn “đã được chứng nhận”, lại phải chạy theo các công nghệ “cao cấp” thay đổi nhanh hơn cả tốc độ quay cổ
      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

    • Mong rằng việc Ladybird dùng cURL sẽ trở thành động lực cải thiện chính cURL, chẳng hạn ở những phần như WebSocket trên h2 đã được nhắc tới
      Đâ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ế
    • Về ý “nếu có một engine trình duyệt đang phát triển thì con đường lấy fingerprint này có thể biến mất”, những gì tôi thấy từ CloudFlare và các bên tương tự gần như ngược lại hoàn toàn
      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
    • Khi nói chuyện với những người này [0], chúng tôi đã bàn về nhiều khác biệt implementation kỳ quặc tạo nên chữ ký, thậm chí bao gồm cả các yếu tố của TCP stack mà ứng dụng ở user space không thể kiểm soát
      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
    • Nhờ vậy mà hy vọng Ladybird sẽ hỗ trợ URL ftp
    • Ladybird không có tài nguyên để cạnh tranh với các trình duyệt hiện nay. Quảng bá thì tốt, nhưng thiếu lợi thế hoặc lý do tồn tại so với Chromium
      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

    • Chỉ khó khi dùng PaaS/IaaS không cung cấp quyền truy cập TCP/IP stack ở mức thấp. Nếu tự vận hành máy chủ thì lấy fingerprint đủ loại thuộc tính TCP/IP rất dễ
      https://en.wikipedia.org/wiki/TCP/IP_stack_fingerprinting
    • Giá trị TTL của gói nhận vào chẳng phải thay đổi tùy theo tình trạng mạng sao? Máy chủ có thể khôi phục giá trị ban đầu của client không?
    • Tại sao TTL được thiết kế để giảm chứ không tăng? Thông thường chẳng phải ta kỳ vọng bên định tuyến lưu lượng quyết định có định tuyến hay không và định tuyến thế nào sao?
  • 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

    • Cloudflare dùng fingerprint TLS JA3/JA4, là hash của nhiều tham số TLS handshake
      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
    • Về cơ bản đó là việc các hãng bảo mật như Cloudflare đang làm, và ngoài ra họ còn lấy fingerprint nhiều hơn bằng các thứ như JavaScript challenge để kiểm tra JavaScript interpreter/DOM
    • Có thể, và các site thực sự đang làm vậy, nhưng việc này rất tệ. Độ tin cậy thấp nên nó chặn hết mọi người không dùng Chrome mới nhất trên Windows mới nhất
      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
    • Công cụ trong bài có vẻ đúng là nhằm tránh kiểu chặn như vậy
  • Đâ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

    • Khoảng 6 tháng trước, tôi từng vào một trang đấu giá của chính phủ yêu cầu Internet Explorer. Đúng là Internet Explorer thật, và trang vẫn đang hoạt động nên dữ liệu đấu giá là mới nhất
      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
    • Bạn chỉ được vào trang nếu dùng phần mềm chúng tôi đã phê duyệt. Còn lại đều bị xem là độc hại. Xuất trình giấy tờ!
      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ạng

  • Bài Show HN lúc đó: https://news.ycombinator.com/item?id=30378562

    • Vào thời điểm đó, năm 2022, nó chỉ dành cho Firefox
  • 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

    • Nghe như thể các nhà phát triển trình duyệt muốn trình duyệt có thể bị nhận dạng bằng dấu vân tay, nhưng đó gần như là điều tự nhiên phát sinh khi những người khác nhau triển khai theo những cách khác nhau
      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

    • Khi đó, website không tiêu tốn nhiều tài nguyên như bây giờ. Tôi xem phản ứng tiêu cực đối với bot gần như là một tác dụng phụ của việc kỳ vọng về trải nghiệm web đã trở nên quá nặng nề
  • 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