← Назад в базу знаний

Cloudflare через IPv6 прокси: обход challenge и парсинг защищённых сайтов

Cloudflare через IPv6 прокси: обход challenge и парсинг защищённых сайтов

Почему Cloudflare стал проблемой для парсеров

Cloudflare защищает примерно 20% всех сайтов в интернете. Для обычного пользователя это невидимый щит. Для парсера — стена с капчей, JS-challenge и TLS-фингерпринтингом.

Механика защиты многослойная. Сначала CDN проверяет репутацию IP по ASN. Потом смотрит на TLS ClientHello — набор шифров, порядок расширений, ALPN. Дальше идёт JS-челлендж: браузер должен выполнить обфусцированный код и вернуть cookie `cf_clearance`. И только тогда запрос проходит.

Датацентровые IP из DigitalOcean, Hetzner, AWS горят на первом слое. Residential-прокси решают проблему, но стоят от \$3 за гигабайт. IPv6 в этом раскладе — недооценённый инструмент.

Чем IPv6 отличается от IPv4 в контексте антибота

У IPv6 гигантский пул адресов. Провайдер выдаёт /64 — это 18 квинтиллионов адресов на одного клиента. Cloudflare физически не может банить подсети /64 целиком, иначе положит легитимных пользователей.

На практике репутация строится не по отдельному адресу, а по префиксу /64 или /48. Свежий /64 от жилого провайдера имеет нейтральную репутацию. Датацентровый /64 — красный флаг.

Второй момент: многие антибот-системы до 2023 года плохо обрабатывали IPv6. Логика была заточена под IPv4. Сейчас дыры закрыли, но инерция осталась — некоторые проверки просто пропускают IPv6-трафик без глубокого анализа.

TLS-фингерпринт важнее IP

Голый IPv6 не спасёт, если у вас Python `requests`. JA3-хеш этого клиента известен всем WAF. Cloudflare сравнивает отпечаток с базой легитимных браузеров.

Что смотреть в ClientHello:

- порядок cipher suites

- список extensions (особенно GREASE-значения)

- supported_versions

- elliptic_curves

- ALPN-протоколы

`requests` с urllib3 даёт JA3 вроде `3b5074b1b5d032e5620f69f9f700ff0e`. Chrome 120 — совсем другой хеш. Разница видна с первого пакета.

Решение — либо curl_cffi с импersonation, либо реальный браузер через Playwright. Первое легче, второе надёжнее.

Практика: curl_cffi через IPv6

Библиотека `curl_cffi` подменяет TLS-отпечаток на браузерный. Плюс поддерживает привязку к IPv6-интерфейсу.

```python

from curl_cffi import requests

proxies = {

"http": "http://[2a01:4f8:c17:1234::1]:8080",

"https": "http://[2a01:4f8:c17:1234::1]:8080"

}

r = requests.get(

"https://example-protected.com/api/data",

impersonate="chrome120",

proxies=proxies,

timeout=30

)

print(r.status_code, r.json())

```

Ключевой параметр — `impersonate`. Без него даже через IPv6 вы получите 403 за 200 мс. С ним — 200 OK, если IP не в чёрном списке.

Проверить, что трафик реально идёт через IPv6, можно так:

```bash

curl -6 -x "http://[2a01:4f8:c17:1234::1]:8080" \

-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \

https://api64.ipify.org?format=json

```

Ответ покажет IPv6-адрес прокси. Если вернулся IPv4 — прокси не поддерживает IPv6-выход, и вся затея бессмысленна.

Когда JS-challenge неизбежен

`cf_clearance` cookie выдаётся после прохождения JS-задачи. Иногда — managed challenge без капчи, иногда — Turnstile. Обойти это без браузера почти нереально.

Playwright с IPv6-прокси работает, но требует настройки. Прокси задаётся на уровне контекста браузера.

```python

from playwright.sync_api import sync_playwright

with sync_playwright() as p:

browser = p.chromium.launch(

headless=True,

args=["--disable-blink-features=AutomationControlled"]

)

context = browser.new_context(

proxy={

"server": "http://[2a01:4f8:c17:1234::1]:8080",

"username": "user",

"password": "pass"

},

user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"

)

page = context.new_page()

page.goto("https://target.com", wait_until="networkidle")

cookies = context.cookies()

print(cookies)

```

Cookie `cf_clearance` живёт 30 минут, привязана к IP и User-Agent. Смена IP — сброс. Смена UA — сброс. Это ломает ротацию прокси, если делать её слишком агрессивно.

Ротация IPv6-адресов внутри /64

Провайдер даёт /64, и все адреса в нём маршрутизируются на ваш сервер. Можно менять исходящий адрес на каждый запрос без переподключения к прокси.

На Linux это делается через `ip -6 addr add`:

```bash

for i in \$(seq 1 100); do

ip -6 addr add 2a01:4f8:c17:1234::\${i}/64 dev eth0

done

```

Дальше в приложении выбираете случайный адрес из пула как source. В `curl` это `--interface`, в Python — `socket.bind()` перед connect.

Подводный камень: Cloudflare считает репутацию по /64. Если с одного префикса летит 1000 запросов в минуту с разных адресов — это выглядит как ботнет. Ротация помогает от per-IP лимитов, но не от префиксных.

Таблица: что работает, а что нет

| Метод | Обход managed challenge | Обход JS challenge | Стоимость |

|-------|------------------------|--------------------|-----------|

| requests + IPv4 DC | нет | нет | низкая |

| requests + IPv6 residential | частично | нет | средняя |

| curl_cffi + IPv6 DC | да | нет | низкая |

| curl_cffi + IPv6 residential | да | иногда | средняя |

| Playwright + IPv6 residential | да | да | высокая |

Цифры приблизительные, зависят от конкретной конфигурации Cloudflare у целевого сайта. Уровень защиты настраивается владельцем — где-то стоит "Essentially Off", где-то "I'm Under Attack".

Реальный пример: парсинг маркетплейса

Сервер на Hetzner, Ubuntu 22.04, IPv6 /64 от провайдера. Цель — сайт на Cloudflare с managed challenge. Первые попытки через `requests` давали 403 с заголовком `cf-mitigated: challenge`.

Причина — JA3-хеш Python. Переписали на curl_cffi с `impersonate="chrome120"`. Задержка выросла с 180 мс до 340 мс (дополнительный TLS handshake с браузерным отпечатком). Но 403 превратились в 200.

Через сутки начались 429. Cloudflare включил rate limiting по /64. Решение — распределить трафик на три /64 от разных провайдеров. Плюс задержка 2-4 секунды между запросами. Пропускная способность упала до 15 запросов в минуту, но стабильность выросла до 99%.

Прокси-слой lexic.ml и IPv6

Собственный IPv6-пул требует ASN, договора с провайдером и настройки BGP. Для большинства задач это избыточно. Готовые IPv6-прокси снимают головную боль — вы получаете /64 или несколько /64 в аренду, с автоматической ротацией адресов внутри префикса.

На lexic.ml IPv6-прокси работают с 2015 года, и за это время пул пережил несколько волн банов Cloudflare. Ключевое — разнообразие ASN. Если все адреса из одного датацентра, толку мало.

Заголовки, которые выдают автоматизацию

Cloudflare смотрит на порядок заголовков. В реальном Chrome он строгий: `Host`, `Connection`, `sec-ch-ua`, `sec-ch-ua-mobile`, `User-Agent`, `Accept`, `Sec-Fetch-Site` и так далее. Python `requests` отправляет их в другом порядке плюс добавляет `Accept-Encoding: gzip, deflate` без `br`.

Проверить свой отпечаток можно на `tls.browserleaks.com` или `httpbin.org/headers`. Если порядок отличается от браузерного — challenge гарантирован.

`curl_cffi` с `impersonate` копирует и порядок заголовков, и их значения. Это одна из причин, почему библиотека обходит то, что `requests` не может.

HTTP/2 и HTTP/3

Cloudflare активно продвигает HTTP/3 поверх QUIC. Некоторые WAF-правила работают только с HTTP/2. Если ваш клиент умеет HTTP/3 — попробуйте, иногда это обходит проверки, заточенные под HTTP/2.

Но есть нюанс: не все прокси пропускают UDP. QUIC требует UDP-транспорт. IPv6-прокси на TCP-only инфраструктуре HTTP/3 не отдадут. Проверяйте поддержку заранее.

Итоговые грабли

Первая — верить, что IPv6 сам по себе решает проблему. Нет. Он лишь один из слоёв. Без правильного TLS-отпечатка и заголовков он бесполезен.

Вторая — ротировать адреса слишком часто. Cloudflare видит паттерн и банит префикс. Умеренность важнее скорости.

Третья — игнорировать `cf_clearance`. Если challenge всё-таки пройден, cookie надо переиспользовать, а не получать заново на каждый запрос. Иначе браузерный фарм выглядит подозрительно.

Четвёртая — забыть про `Retry-After`. При 429 Cloudflare указывает, сколько ждать. Игнорирование приводит к эскалации бана.

Пятая — использовать headless-браузер без маскировки. `navigator.webdriver`, отсутствие плагинов, странный WebGL-рендер — всё это палится. Playwright с `--disable-blink-features=AutomationControlled` и stealth-плагином частично лечит, но не полностью.

✔️Купить прокси