Тема: Cloudflare WAF (Web Application Firewall) и возможность из php пройти
Как работает WAF Cloudflare ? WAF проверяет TLS-отпечаток на этапе рукопожатия. Стандартный cURL в PHP имеет отпечаток, который не совпадает ни с одним браузером. Поэтому сервер, даже не посмотрев на ваши заголовки и cookie, отбрасывает соединение с ошибкой 403 Forbidden. TLS-отпечаток (так называемый JA3 fingerprint). Браузер и cURL устанавливают TLS-соединение по-разному (разный набор шифров, расширений, версия TLS). Защита видит, что «отпечаток» не совпадает с заявленным User-Agent, и блокирует запрос. Кстати mail.ru теперь тоже так работает.
Решить проблему можно за деньги = Proxy-провайдеры: Некоторые сервисы (например, NikaProxy) продают "TLS-Pro" тарифы, где они подменяют ваш TLS-отпечаток на браузерный, чтобы запросы не блокировались .
Инструменты проверки: Существуют утилиты (например, ja3-fingerprint-checker), которые показывают, как ваш HTTP-клиент выглядит со стороны защитных систем .
Решить можно бесплатно, обновлением софта на своем сервере.
1. Использование curl-impersonate. Это специальная модификация cURL, которая может полностью имитировать рукопожатие Chrome, Firefox, Edge и Safari. Нужно установить curl-impersonate на сервер или использовать альтернативную библиотеку для PHP.
Скачать сборку curl-impersonate можно https://github.com/lexiforest/curl-impersonate/releases Например для windows ищем curl-impersonate-v2.2.3.x86_64-win32.tar.gz В этом архиве curl-impersonate.exe и куча батников, которые дадут разные, реальные браузеры например curl_chrome120.bat или curl_chrome146.bat . Все это размещаем в папке C:\curl-impersonate\
Далее ставим Composer (нужен для установки PHP-обёртки). Скачайте Composer-Setup.exe с официального сайта getcomposer.org. Запустите установщик, она найдет сам php. После установки проверить composer -V, должна отобразиться версия Composer и путь к PHP. Обёртка kelvinzer0/curl-impersonate-php — это простая библиотека, которая запускает скачанный .exe через exec() и возвращает ответ . Когда все настроено, используйте обёртку для чтения сайта например такой функцией
use CurlImpersonate\CurlImpersonate;
function fetch_embed_via_impersonate($url, $referer, $cookies = '') {
$curl = new CurlImpersonate();
$curl->setopt(CurlImpersonate::OPT_ENGINE, 'C:\\curl-impersonate\\curl_chrome116.exe');
$curl->setopt(CurlImpersonate::OPT_URL, $url);
$curl->setopt(CurlImpersonate::OPT_METHOD, 'GET');
$curl->setopt(CurlImpersonate::OPT_TIMEOUT, 25);
// Заголовки — как в вашем текущем коде
$headers = [
'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'accept-language: ru,ru-RU;q=0.9,en-US;q=0.8,en;q=0.7',
'referer: ' . $referer,
'sec-ch-ua: "Chromium";v="116", "Not A(Brand";v="99"',
'sec-ch-ua-mobile: ?0',
'sec-ch-ua-platform: "Windows"',
'sec-fetch-dest: iframe',
'sec-fetch-mode: navigate',
'sec-fetch-site: cross-site',
'upgrade-insecure-requests: 1',
'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
];
foreach ($headers as $h) {
$curl->setopt(CurlImpersonate::OPT_HEADER, $h); // или через массив, см. документацию
}
$html = $curl->execStandard();
// Извлеките cookie из ответа, если нужно, или используйте опцию COOKIEJAR
return $html;
}.
обёртка не ведёт cookie-jar автоматически. Вам нужно либо передавать cookie вручную (как заголовок Cookie:), либо использовать опции OPT_COOKIEJAR/OPT_COOKIEFILE, если они поддерживаются версией обёртки
Есть более современная обёртка farhaanaliii/curl-cffi, которая использует PHP FFI и загружает libcurl-impersonate.dll напрямую, без запуска .exe . Она требует PHP 8.1+ и включённого расширения ffi. Этот пакет распространяется через Composer, как и любой другой PHP-пакет. На странице Packagist указаны его требования и версия https://packagist.org/packages/farhaanaliii/curl-cffi В папке вашего проекта выполните команду:bash
composer require farhaanaliii/curl-cffi
Следует ожидать, что в очередной версии php этот механизм будет встроен и защита сайтов WAF полностью потеряет актуальность.