Как правильно отправить POST запрос с CSRF токеном для Laravel?
Добрый день. Пытаюсь отправить POST запрос на другой сайт, через cURL. Адрес https://promokod.pikabu.ru/coupon/5ka/Lty7boqhMLLy хочу получить ответ в котором есть json, оттуда вытащить ключ promocode.
Предполагаю, что требуется для начала получить CSRF token. Захожу на страницу и получаю этот токен, пытаюсь отправить, но в ответ получаю ошибку { "message": "CSRF token mismatch." }. Насколько я понимаю, данный сайт сделан на Laravel.
Делаю так:
<?php // Инициализация cURL-сессии для GET-запроса страницы и извлечения CSRF-токена $ch = curl_init(); // Установка параметров cURL-сессии для GET-запроса curl_setopt($ch, CURLOPT_URL, 'https://promokod.pikabu.ru/shops/5ka'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); // Выполнение GET-запроса $response = curl_exec($ch); // Закрытие cURL-сессии curl_close($ch); // Парсинг страницы для извлечения CSRF-токена preg_match('/<meta name="csrf-token" content="(.+?)">/', $response, $matches); if (isset($matches[1])) { $csrf_token = $matches[1]; } else { die("CSRF-токен не найден"); } // Заголовки для POST-запроса $headers = [ "Accept: application/json, text/plain, */*", "Accept-Encoding: gzip, deflate, br", "Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7", "Connection: keep-alive", "Content-Length: 2", "Content-Type: application/json;charset=UTF-8", "Cookie: pcid=4yDnaZt3zv2; ...", "DNT: 1", "Host: promokod.pikabu.ru", "Origin: https://promokod.pikabu.ru", "Referer: https://promokod.pikabu.ru/shops/5ka", "Sec-Fetch-Dest: empty", "Sec-Fetch-Mode: cors", "Sec-Fetch-Site: same-origin", "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", "X-Requested-With: XMLHttpRequest", "X-XSRF-TOKEN: " . $csrf_token ]; // Инициализация cURL-сессии для POST-запроса $ch = curl_init(); // Установка параметров cURL-сессии для POST-запроса curl_setopt($ch, CURLOPT_URL, 'https://promokod.pikabu.ru/coupon/5ka/Lty7boqhMLLy'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([])); // Данные запроса (пустой JSON в данном случае) // Выполнение POST-запроса $response = curl_exec($ch); // Закрытие cURL-сессии curl_close($ch); // Обработка ответа от сервера echo $response; ?> |
<?php // Инициализация cURL-сессии для GET-запроса страницы и извлечения CSRF-токена $ch = curl_init(); // Установка параметров cURL-сессии для GET-запроса curl_setopt($ch, CURLOPT_URL, 'https://promokod.pikabu.ru/shops/5ka'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); // Выполнение GET-запроса $response = curl_exec($ch); // Закрытие cURL-сессии curl_close($ch); // Парсинг страницы для извлечения CSRF-токена preg_match('/<meta name="csrf-token" content="(.+?)">/', $response, $matches); if (isset($matches[1])) { $csrf_token = $matches[1]; } else { die("CSRF-токен не найден"); } // Заголовки для POST-запроса $headers = [ "Accept: application/json, text/plain, */*", "Accept-Encoding: gzip, deflate, br", "Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7", "Connection: keep-alive", "Content-Length: 2", "Content-Type: application/json;charset=UTF-8", "Cookie: pcid=4yDnaZt3zv2; ...", "DNT: 1", "Host: promokod.pikabu.ru", "Origin: https://promokod.pikabu.ru", "Referer: https://promokod.pikabu.ru/shops/5ka", "Sec-Fetch-Dest: empty", "Sec-Fetch-Mode: cors", "Sec-Fetch-Site: same-origin", "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", "X-Requested-With: XMLHttpRequest", "X-XSRF-TOKEN: " . $csrf_token ]; // Инициализация cURL-сессии для POST-запроса $ch = curl_init(); // Установка параметров cURL-сессии для POST-запроса curl_setopt($ch, CURLOPT_URL, 'https://promokod.pikabu.ru/coupon/5ka/Lty7boqhMLLy'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([])); // Данные запроса (пустой JSON в данном случае) // Выполнение POST-запроса $response = curl_exec($ch); // Закрытие cURL-сессии curl_close($ch); // Обработка ответа от сервера echo $response; ?>
Заголовки запроса, которые посылает браузер:
Тот токен, что я вижу на странице, отличается от того, что посылается браузером. Отличается и размером и внешним видом, я так понимаю, он возможно генерируется как-то. Подскажите пожалуйста, как получить правильный ответ от сервера.
Дополнительно:
токен действителен в течение текущей сессии. вы второй запрос делаете отдельно.
нужно куку сохранить. CURLOPT_COOKIEFILE или типа того, не помню опцию.
2. Когда вы уже забудете про curl?
Я выше написал - вам нужно сохранять куки между запросами. Для хранения печенек у курла есть специальная настройка. Собственно весь пример будет заключаться в написании этой опции (там их кстати две.Я хз какая реально нужна и для чего они различаются, указываю обе).
Ответы:
csrf-token из html не используется
смотрите cookies которые присылает сервер при GET-запросе к https://promokod.pikabu.ru/shops/5ka
в заголовках приходит Set-Cookie: XSRF-TOKEN=
curl -L -I "https://promokod.pikabu.ru/shops/5ka" HTTP/1.1 200 OK Server: nginx Content-Type: text/html; charset=UTF-8 Connection: keep-alive Vary: Accept-Encoding Cache-Control: no-cache, private Date: Fri, 06 Oct 2023 12:56:29 GMT X-RateLimit-Limit: 60 X-RateLimit-Remaining: 58 Set-Cookie: XSRF-TOKEN=eyJpdiI6ImZuTllpTWRIb2ZDalF5.......TkyOWY3In0%3D; expires=Fri, 13-Oct-2023 12:56:29 GMT; Max-Age=604800; path=/ |
curl -L -I "https://promokod.pikabu.ru/shops/5ka" HTTP/1.1 200 OK Server: nginx Content-Type: text/html; charset=UTF-8 Connection: keep-alive Vary: Accept-Encoding Cache-Control: no-cache, private Date: Fri, 06 Oct 2023 12:56:29 GMT X-RateLimit-Limit: 60 X-RateLimit-Remaining: 58 Set-Cookie: XSRF-TOKEN=eyJpdiI6ImZuTllpTWRIb2ZDalF5.......TkyOWY3In0%3D; expires=Fri, 13-Oct-2023 12:56:29 GMT; Max-Age=604800; path=/
Это значение и надо использовать для дальнейшего POST-запроса
- Сейчас я делаю так:
$userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'; // Используем cURL для создания сессии $ch = curl_init(); // Устанавливаем параметры для GET-запроса curl_setopt_array($ch, array( CURLOPT_URL => 'https://promokod.pikabu.ru/shops/5ka', CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, CURLOPT_USERAGENT => $userAgent, )); // Выполняем GET-запрос $response = curl_exec($ch); // Парсим заголовки ответа, чтобы найти и сохранить cookie preg_match('/Set-Cookie:s*(XSRF-TOKEN=[^;]+)/', $response, $matches); $cookieXSRF = isset($matches[1]) ? $matches[1] : ''; preg_match('/Set-Cookie:s*(laravel_session=[^;]+)/', $response, $matches); $cookieLaravelSession = isset($matches[1]) ? $matches[1] : ''; if (empty($cookieXSRF) || empty($cookieLaravelSession)) { die("Не удалось получить XSRF-TOKEN и/или laravel_session cookies."); } // Имитируем пустой JSON-запрос $jsonData = json_encode([]); // Устанавливаем параметры для POST-запроса curl_setopt_array($ch, array( CURLOPT_URL => 'https://promokod.pikabu.ru/coupon/5ka/Lty7boqhMLLy', CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => array( 'Cookie: ' . $cookieXSRF . '; ' . $cookieLaravelSession, // Передаем оба cookie 'User-Agent: ' . $userAgent, // Устанавливаем User-Agent ), CURLOPT_POSTFIELDS => $jsonData, // Передаем пустой JSON-запрос )); // Выполняем POST-запрос $response = curl_exec($ch); // Проверяем наличие ошибок if ($response === false) { die('Ошибка cURL: ' . curl_error($ch)); } // Закрываем соединение cURL curl_close($ch); // Выводим ответ на экран echo $response;
$userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'; // Используем cURL для создания сессии $ch = curl_init(); // Устанавливаем параметры для GET-запроса curl_setopt_array($ch, array( CURLOPT_URL => 'https://promokod.pikabu.ru/shops/5ka', CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, CURLOPT_USERAGENT => $userAgent, )); // Выполняем GET-запрос $response = curl_exec($ch); // Парсим заголовки ответа, чтобы найти и сохранить cookie preg_match('/Set-Cookie:s*(XSRF-TOKEN=[^;]+)/', $response, $matches); $cookieXSRF = isset($matches[1]) ? $matches[1] : ''; preg_match('/Set-Cookie:s*(laravel_session=[^;]+)/', $response, $matches); $cookieLaravelSession = isset($matches[1]) ? $matches[1] : ''; if (empty($cookieXSRF) || empty($cookieLaravelSession)) { die("Не удалось получить XSRF-TOKEN и/или laravel_session cookies."); } // Имитируем пустой JSON-запрос $jsonData = json_encode([]); // Устанавливаем параметры для POST-запроса curl_setopt_array($ch, array( CURLOPT_URL => 'https://promokod.pikabu.ru/coupon/5ka/Lty7boqhMLLy', CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => array( 'Cookie: ' . $cookieXSRF . '; ' . $cookieLaravelSession, // Передаем оба cookie 'User-Agent: ' . $userAgent, // Устанавливаем User-Agent ), CURLOPT_POSTFIELDS => $jsonData, // Передаем пустой JSON-запрос )); // Выполняем POST-запрос $response = curl_exec($ch); // Проверяем наличие ошибок if ($response === false) { die('Ошибка cURL: ' . curl_error($ch)); } // Закрываем соединение cURL curl_close($ch); // Выводим ответ на экран echo $response;
и получаю 419 Page Expired
- Александр Андропов, добавьте CURLOPT_VERBOSE=>true и посмотрите что у вас вообще на сервер улетает
- Дмитрий, странно, что при добавлении этой опции вообще ничего не произошло. Экран такой же как на скрине выше.
- Ну либо я с названием опции ошибся, либо вы не туда вставили
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос


Для отправки POST запроса с CSRF токеном в Laravel, вам необходимо включить CSRF защиту в вашем приложении и передать токен вместе с запросом.
Прежде всего, убедитесь, что в вашем шаблоне Blade формы добавлен токен CSRF с помощью директивы @csrf:
@csrf <!-- Остальные поля формы -->@csrf <!-- Остальные поля формы -->
Затем, в JavaScript коде (или в другом месте, где вы отправляете запрос) вы можете получить значение CSRF токена из мета-тега в вашем HTML коде и добавить его к вашему POST запросу. Например, если вы используете jQuery для отправки запроса, код может выглядеть следующим образом:
var token = $('meta[name="csrf-token"]').attr('content'); $.ajax({ url: '/your-route', type: 'POST', data: { _token: token, // Другие данные для отправки }, success: function(response) { // Обработка успешного ответа }, error: function(xhr) { // Обработка ошибки } });
Обратите внимание, что в данном примере мы добавляем токен в объект данных с ключом '_token'. Laravel автоматически проверит наличие этого токена при отправке POST запроса и защитит ваше приложение от CSRF атак.
Таким образом, вы можете отправить POST запрос с CSRF токеном для Laravel, следуя вышеприведенным инструкциям.