Some checks failed
Published content check / validate (push) Failing after 3s
Обновить правила репозитория и подписи исходников в 99 заметках, не затрагивая пользовательские незакоммиченные файлы. Сделать Forgejo Actions содержательным: проверять опубликованный commit, а не пустое рабочее дерево после checkout.
149 lines
14 KiB
Markdown
149 lines
14 KiB
Markdown
---
|
||
date: 2026-07-16
|
||
tags:
|
||
- dpi
|
||
- tls
|
||
- ja3
|
||
- ja4
|
||
- fingerprint
|
||
- curl
|
||
- tool
|
||
aliases:
|
||
- curl-impersonate
|
||
- curl impersonate
|
||
- Проверка блокировки по JA3/JA4
|
||
- Имитация TLS-отпечатка браузера через curl
|
||
link: https://github.com/lwthiker/curl-impersonate
|
||
---
|
||
|
||
# 🥷 curl-impersonate — curl, притворяющийся браузером (проверка блокировок по TLS-отпечатку)
|
||
|
||
> [!info] О чём заметка
|
||
> **curl-impersonate** — это специальная сборка `curl`, которая воспроизводит сетевой «почерк» настоящих браузеров: их TLS-рукопожатие (отпечатки **JA3/JA4**), параметры HTTP/2 и порядок заголовков. Заметка объясняет, что это за инструмент и как им **проверять**, блокирует ли DPI ваше соединение именно по отпечатку клиента, а не по адресу или содержимому. Теория самого механизма блокировки по отпечатку разобрана в [[DPI/browser-ja4-fingerprint-block|кейсе с JA4-блокировкой]] и [[DPI/dpi-analysis-pipeline|воронке проверок DPI]] — здесь только инструмент.
|
||
|
||
> [!warning] Статус проекта
|
||
> Последний релиз оригинального `lwthiker/curl-impersonate` — **v0.6.1 (март 2024)**, поэтому «свежие» профили в нём соответствуют браузерам того времени (вплоть до Chrome 116, Firefox 117). Отпечатки браузеров устаревают: реальный Chrome 2026 года даёт уже другой JA4, чем профиль `chrome116`. Для актуальных отпечатков смотрите активные форки/наследники проекта (например, экосистему `curl_cffi` в Python). Проверяйте, какой именно отпечаток отдаёт ваша сборка, прежде чем делать выводы.
|
||
|
||
## TL;DR
|
||
|
||
- Обычный `curl` имеет **свой уникальный TLS-отпечаток**, совсем не похожий на браузерный. Поэтому по «сигналу 2» (фингерпринт клиента) он и браузер выглядят для DPI по-разному.
|
||
- **curl-impersonate** подделывает рукопожатие так, чтобы оно **совпадало с конкретным браузером** (Chrome, Edge, Firefox, Safari) — вплоть до набора TLS-расширений, шифронаборов, кривых и параметров HTTP/2.
|
||
- Главная польза для темы обхода блокировок — **диагностика**: можно за секунды проверить, реагирует ли DPI на **отпечаток клиента**. Если сайт открывается через `curl_ff117`, но не через `curl_chrome116` (или наоборот) — значит блокировка идёт по JA3/JA4, а не по IP или SNI.
|
||
- Использование — через готовые wrapper-скрипты: `curl_chrome116 https://example.com`, `curl_ff117 …`, `curl_safari15_3 …`.
|
||
- Есть и библиотека `libcurl-impersonate.so` — её можно подсунуть чужому приложению через `LD_PRELOAD` + `CURL_IMPERSONATE=chrome116`, не меняя код приложения.
|
||
|
||
## Зачем это нужно: проблема отпечатка клиента
|
||
|
||
Многие серверы и системы фильтрации (в том числе DPI) отличают «настоящий браузер» от «скрипта/бота» не по паролю и не по IP, а по **TLS-отпечатку** — характеристике самого TLS-рукопожатия.
|
||
|
||
**JA3 / JA4** — это стандартизированные способы свернуть параметры первого пакета TLS (`ClientHello`) в короткую строку-хеш: какие версии TLS предложены, в каком порядке идут шифронаборы, какие расширения включены, какие эллиптические кривые и т.д. У каждой программы этот набор свой и довольно стабильный, поэтому по нему можно опознать клиента, даже не расшифровывая трафик.
|
||
|
||
**Проще говоря:** ещё до того, как между вами и сайтом установится шифрование, ваша программа «представляется» — рассказывает, что она умеет и в каком порядке. Этот «акцент» у Chrome, Firefox и обычного `curl` разный, и наблюдатель посередине слышит разницу, не понимая ни слова из самого разговора.
|
||
|
||
Проблема в том, что **обычные HTTP-клиенты** (`curl`, `requests`, `Go net/http`) звучат совершенно не как браузер. Поэтому:
|
||
|
||
- сервисы с анти-бот-защитой их блокируют, отдавая капчу или `403`;
|
||
- а DPI, наоборот, может блокировать **именно браузерный** отпечаток (как в [[DPI/browser-ja4-fingerprint-block|кейсе, где Chromium не открывал сайт, а `curl` открывал]]).
|
||
|
||
curl-impersonate решает обе стороны задачи: он позволяет `curl`-у звучать как выбранный браузер — а значит, воспроизвести ровно тот отпечаток, который вы хотите проверить.
|
||
|
||
## Как реализована имитация
|
||
|
||
curl-impersonate добивается совпадения на трёх уровнях сразу — потому что подделать только заголовки недостаточно, отпечаток считается ниже, на уровне TLS.
|
||
|
||
- **TLS-уровень.** Сборка под Chrome компилируется с **BoringSSL** (TLS-библиотека Google), под Firefox — с **NSS** (TLS-библиотека Mozilla). Это не косметика: сам стек TLS берётся «родной» для имитируемого браузера, плюс правятся расширения, шифронаборы и кривые, чтобы `ClientHello` совпал байт-в-байт с оригиналом.
|
||
- **HTTP/2-уровень.** Подгоняются параметры HTTP/2-соединения (SETTINGS, WINDOW_UPDATE) и **порядок псевдо-заголовков** — по ним тоже строят отпечаток (см. [[DPI/tspu-h2-h3-fingerprint-hypothesis|гипотезу об отпечатке HTTP/2 и HTTP/3]]).
|
||
- **HTTP-заголовки.** Wrapper-скрипты выставляют набор и порядок заголовков (`User-Agent`, `Accept`, `sec-ch-*` и т.д.) как у настоящего браузера.
|
||
|
||
**Проще говоря:** нельзя просто подменить `User-Agent` и стать Chrome — DPI и анти-бот-системы смотрят на то, *как* устроено само шифрованное рукопожатие, а не на то, что программа о себе пишет. curl-impersonate чинит именно рукопожатие, поэтому обмануть проверку получается.
|
||
|
||
## Поддерживаемые браузеры (в оригинальной сборке v0.6.1)
|
||
|
||
| Браузер | Профили (версии) |
|
||
|---|---|
|
||
| **Chrome** | 99, 100, 101, 104, 107, 110, 116 (Win10); 99 (Android 12) |
|
||
| **Edge** | 99, 101 (Win10) |
|
||
| **Firefox** | 91 ESR, 95, 98, 100, 102, 109, 117 (Win10) |
|
||
| **Safari** | 15.3, 15.5 (macOS) |
|
||
|
||
Полный актуальный список профилей лежит в файле `browsers.json` в репозитории. Имя профиля (например, `chrome116`) — это и есть аргумент для библиотеки и суффикс wrapper-скрипта.
|
||
|
||
## Установка
|
||
|
||
Готовые бинарники для Linux и macOS (Intel) есть на [странице релизов](https://github.com/lwthiker/curl-impersonate/releases). Варианты:
|
||
|
||
- **Docker** (быстро попробовать, ничего не ставя в систему):
|
||
|
||
```bash
|
||
docker pull lwthiker/curl-impersonate:0.6-chrome
|
||
docker run --rm lwthiker/curl-impersonate:0.6-chrome curl_chrome110 https://www.wikipedia.org
|
||
```
|
||
|
||
- **Arch Linux (AUR):** `yay -S curl-impersonate-bin`
|
||
- **macOS (Homebrew, только Chrome):** `brew tap shakacode/brew` затем `brew install curl-impersonate`
|
||
- **Зависимости для Firefox-сборки на Linux** (нужен NSS):
|
||
|
||
```bash
|
||
sudo apt install libnss3 nss-plugin-pem ca-certificates
|
||
```
|
||
|
||
## Использование
|
||
|
||
### Через wrapper-скрипты (самый простой путь)
|
||
|
||
Для каждого профиля есть готовый скрипт-обёртка, который уже подставляет нужные TLS-опции и заголовки:
|
||
|
||
```bash
|
||
curl_chrome116 https://www.wikipedia.org
|
||
curl_ff117 https://www.wikipedia.org
|
||
curl_safari15_3 https://www.wikipedia.org
|
||
```
|
||
|
||
Дополнительные флаги передаются как обычному `curl`:
|
||
|
||
```bash
|
||
curl_chrome116 -H "Custom-Header: value" -v https://example.com
|
||
```
|
||
|
||
### Как проверить блокировку по отпечатку (сценарий диагностики)
|
||
|
||
- [ ] Открыть проблемный адрес обычным `curl` — записать результат (успех/`RST`/таймаут).
|
||
- [ ] Повторить через `curl_chrome116` (браузерный отпечаток Chromium).
|
||
- [ ] Повторить через `curl_ff117` (отпечаток Firefox) — у него **другой** JA4.
|
||
- [ ] Сравнить: если один профиль проходит, а другой стабильно рвётся (`TCP Retransmission` → `RST`) при том же IP и SNI — блокировка идёт **по отпечатку клиента**, а не по адресу. Это ровно тот механизм, что описан в [[DPI/browser-ja4-fingerprint-block|кейсе JA4-блокировки]].
|
||
|
||
### Через libcurl (для своих программ)
|
||
|
||
В комплекте есть `libcurl-impersonate.so` с дополнительной функцией:
|
||
|
||
```c
|
||
CURLcode curl_easy_impersonate(struct Curl_easy *data,
|
||
const char *target, // напр. "chrome116"
|
||
int default_headers); // ставить ли браузерные заголовки
|
||
```
|
||
|
||
А чужое приложение, использующее libcurl, можно заставить имитировать браузер **без правки его кода** — через подмену библиотеки на Linux:
|
||
|
||
```bash
|
||
LD_PRELOAD=/path/to/libcurl-impersonate.so \
|
||
CURL_IMPERSONATE=chrome116 \
|
||
my_app
|
||
```
|
||
|
||
Переменная `CURL_IMPERSONATE_HEADERS=no` отключает автоматические браузерные заголовки, если вы хотите задать их вручную.
|
||
|
||
> [!tip] Вердикт: это диагностический инструмент, а не средство обхода
|
||
> curl-impersonate удобен, чтобы **подтвердить или опровергнуть гипотезу**, что вас режут по JA3/JA4-отпечатку. Для повседневного обхода DPI он не нужен — там применяют другие подходы (uTLS/REALITY-фингерпринт в VLESS, десинхронизацию в Zapret). Но как «пробник» для воспроизведения конкретного отпечатка он незаменим: даёт быстрый, скриптуемый способ послать в сеть именно тот `ClientHello`, который вы хотите протестировать.
|
||
|
||
## 📚 См. также
|
||
|
||
- [[DPI/browser-ja4-fingerprint-block|Блокировка по JA4-отпечатку браузера (кейс wireflow.space)]] — зачем вообще воспроизводить отпечаток: реальный случай, где Chromium резался, а `curl` проходил
|
||
- [[DPI/dpi-analysis-pipeline|Как DPI анализирует соединение: воронка проверок]] — где в цепочке фильтрации стоит проверка отпечатка клиента
|
||
- [[DPI/tspu-h2-h3-fingerprint-hypothesis|Гипотеза об отпечатке HTTP/2 и HTTP/3]] — второй уровень, который тоже имитирует curl-impersonate
|
||
- 🔗 [curl-impersonate на GitHub](https://github.com/lwthiker/curl-impersonate) — исходники, релизы, `browsers.json`
|
||
- 🔗 [Страница релизов](https://github.com/lwthiker/curl-impersonate/releases) — готовые бинарники и Docker-образы
|
||
|
||
---
|
||
|
||
> [!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ
|
||
> При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование и скачивание всего репозитория одним zip-архивом доступны в Forgejo: [исходник этой заметки](https://git.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/DPI/curl-impersonate.md) · [весь репозиторий](https://git.zapret.moe/zapretdiscordyoutube/todo/src/branch/main).
|