EnglishРусский Map

surf

title
surf
type
toolbox
summary
HTTP-клиент на Go, маскирующийся под Chrome и Firefox вплоть до TLS-рукопожатия и пакетов QUIC
tags
go, http-client, tls-fingerprinting, browser-impersonation, scraping, quic, watchlist
language
Go
license
MIT
created
2026-05-06
updated
2026-07-29
lang
ru
translation_of
surf
source_updated
2026-07-29
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Библиотека HTTP-клиента на Go, которая имитирует настоящие браузеры вплоть до TLS-рукопожатия и начального пакета QUIC. Нацелена на ту же нишу, что и curl-impersonate и tls-client: веб-автоматизация и скрейпинг сайтов, снимающих фингерпринты клиентов (Cloudflare, Akamai, PerimeterX, DataDome). Имитирует Chrome v145 и Firefox v148 на Windows, macOS, Linux, Android и iOS, с фреймами HTTP/2 SETTINGS, сохранением порядка заголовков и полноценным HTTP/3 поверх QUIC.

Что делает

Стандартный net/http.Client легко выдаёт себя фингерпринтом: его TLS ClientHello, HTTP/2 SETTINGS и порядок заголовков неизменны и не совпадают ни с одним реальным браузером. Системы защиты от ботов вычисляют хеши JA3/JA4 по TLS-рукопожатию и HTTP/2-фингерпринты по содержимому фреймов, поэтому трафик Go сразу выделяется. SURF заменяет транспорт на такой, который выдаёт побайтово эквивалентные рукопожатия для выбранной комбинации версии браузера и ОС, включая вариант QUIC для сайтов только с HTTP/3.

Библиотека также оборачивает жизненный цикл запроса в fluent builder API и модель ошибок на основе типа Result (g.Result[T]), взятую из enetx/g, поэтому работа с ней совсем не похожа на стандартный net/http.

Как устроен

TLS-фингерпринтинг опирается на uTLS (refraction-networking/utls) - стандартный форк для Go, предоставляющий доступ к спецификациям ClientHello. SURF выбирает HelloID или полную HelloSpec под каждую комбинацию браузера и ОС. Фингерпринты JA3/JA4 также можно задавать явно или рандомизировать.

QUIC/HTTP/3 использует quic-go с параметрами, подогнанными под браузер: порядок заголовков, порядок фреймов, значения SETTINGS и фингерпринт JA4QUIC, сформированный из начального пакета (Initial Packet) и TLS ClientHello. Поддерживаются SOCKS5 UDP-прокси, благодаря чему HTTP/3 остаётся доступен и за прокси; при использовании HTTP-прокси происходит автоматический откат к HTTP/2.

HTTP/2 настраивается на уровне фреймов SETTINGS: размер таблицы заголовков, включение push, начальный размер окна, максимальное число параллельных потоков и так далее - всё это задаётся в пресетах браузеров в точности по реальным значениям, отправляемым Chrome и Firefox.

Порядок заголовков сохраняется от начала до конца. Большинство HTTP-библиотек для Go нормализуют порядок заголовков через http.Header из стандартной библиотеки (который представляет собой map); SURF использует форк enetx/http, сохраняющий исходный порядок, поскольку антибот-системы учитывают последовательность заголовков как часть фингерпринта.

Builder API выстраивает цепочку конфигурации: surf.NewClient().Builder().Impersonate().Chrome().JA().Randomized().HTTP2Settings()...Build(). Middleware подключаются через .With(fn, priority...) как хуки на уровне запроса, ответа или всего клиента.

Выход в Std() преобразует настроенный клиент SURF обратно в *net/http.Client для использования со сторонними библиотеками, требующими типы из стандартной библиотеки. Большинство возможностей маскировки фингерпринта при этом сохраняются; логика повторных попыток (retry), кэширование ответов, отслеживание удалённого адреса и замеры времени - нет.

Базовый стек: enetx/http (форк стандартного пакета HTTP), quic-go, uTLS, enetx/g (типы Result/Option и утилиты для строк).

Применение

Базовая имитация Chrome:

client := surf.NewClient().
    Builder().
    Impersonate().Chrome().
    Build().Unwrap()

resp := client.Get("https://example.com").Do()
if resp.IsOk() {
    fmt.Println(resp.Ok().Body.String().Unwrap())
}

Chrome под iOS с принудительным HTTP/3 и прокси SOCKS5 UDP:

client := surf.NewClient().
    Builder().
    Impersonate().IOS().Chrome().
    Proxy("socks5://127.0.0.1:1080").
    ForceHTTP3().
    Build().Unwrap()

Сессия с хранилищем cookie, повторными попытками и кэшем тела ответа:

client := surf.NewClient().
    Builder().
    Impersonate().Firefox().
    Session().
    Retry(3, 2*time.Second).
    CacheBody().
    Build().Unwrap()

Загрузка multipart со смешанными источниками:

mp := surf.NewMultipart().
    Field("description", "Files").
    File("document", g.NewFile("/path/doc.pdf")).
    FileBytes("data", "data.json", g.Bytes(`{"k":"v"}`))

resp := client.Post("https://api.example.com/upload").Multipart(mp).Do()

Ограничения

  • Требуется Go 1.25+.
  • Целями для имитации служат Chrome v145 и Firefox v148; поддержка актуальности при выходе новых версий браузеров целиком лежит на мейнтейнере.
  • API с типом Result (g.Result[T] из enetx/g) не идиоматичен для Go и затягивает нетривиальную зависимость с generic-утилитами. Для интеграции в существующие кодовые базы потребуются adapter-shim'ы.
  • Проект одного автора (Enetx). Активно развивается, но bus factor равен 1.
  • При переходе через Std() теряются повторные попытки, кэширование тела ответа, удалённый адрес и тайминги.
  • TLS-фингерпринтинг через uTLS - постоянно ускользающая цель: разработчики защит от ботов регулярно обновляют механизмы детекта, и работающая маскировка сегодня не гарантирует успеха в следующем квартале.

Связи

Относится к той же сфере обхода фингерпринтинга, что и прокси-ядро в sing-box, руководства по VLESS-кластерам в xray-tutorial и более широкий инструментарий в russia-vpn-bypass-state-2026-04 - хотя те работают на уровне транспортных протоколов, тогда как SURF действует на прикладном уровне HTTP. Полезен для обвязок агентов, создающих скрейперы; по части оркестрации см. sandboxing-ai-agents.

Репозиторий

github.com/enetx/surf - Go, MIT, 1.7k звёзд (88 форков). Один автор, активная разработка.

Внесён в watchlist из-за bus factor 1 на фоне постоянной гонки версий браузеров: фингерпринты необходимо непрерывно обновлять вслед за релизами Chrome и Firefox.