Вход с помощью PHP curl и токена CSRF

Я хочу, чтобы вход с PHP-скрипта на другой веб-сайт, но я всегда получаю этот ответ:

403 Error: CSRF token mismatch 

Я извлекаю токен CSRF из скрытого поля на веб-сайте, но, похоже, он ошибается. Это мой код:

 $username = "testuser"; $password = "testpass"; $path = "c:\\test\\"; $url="http://itw.me/login"; $field='_csrf'; $html=file_get_contents( $url ); libxml_use_internal_errors( true ); $dom=new DOMDocument; $dom->validateOnParse=false; $dom->recover=true; $dom->formatOutput=false; $dom->loadHTML( $html ); libxml_clear_errors(); $xpath=new DOMXPath( $dom ); $col=$xpath->query('//input[@name="'.$field.'"]'); foreach( $col as $node ) $csrftoken=$node->getAttribute('value'); echo "-".$csrftoken."-"; $postinfo = "email=".$username."&password=".$password."&_csrf=".$csrftoken; $cookie_file_path = $path."/cookie.txt"; $ch = curl_init(); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_NOBODY, false); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file_path); curl_setopt($ch, CURLOPT_COOKIE, "cookiename=0"); curl_setopt($ch, CURLOPT_USERAGENT,"Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_REFERER, $_SERVER['REQUEST_URI']); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postinfo); curl_exec($ch); curl_setopt($ch, CURLOPT_URL, "http://itw.me"); $html = curl_exec($ch); print($html); curl_close($ch); 

Вы делаете свой первый запрос с file_get_contents и вторым запросом cURL.

Вы создали банку cookie для второго запроса, но не для первого запроса. Следовательно, каждый из этих двух запросов начинает новую сессию.

Точки CSRF хранятся в сеансе сервером, на который вы делаете запрос, поэтому маркер, который вы получаете первым, не будет соответствовать токену в сеансе для второго запроса.

Тебе нужно:

  • Использовать cURL последовательно
  • Используйте ту же самую банку cookie для обоих запросов

теперь он работает!

 $username = "user"; $password = "pass"; $url = "http://url.com/login"; $cookie= "c:\\cookies.txt"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); if (curl_errno($ch)) die(curl_error($ch)); $dom = new DomDocument(); $dom->loadHTML($response); $tokens = $dom->getElementsByTagName("meta"); for ($i = 0; $i < $tokens->length; $i++) { $meta = $tokens->item($i); if($meta->getAttribute('name') == 'csrf-token') $token = $meta->getAttribute('content'); } $postinfo = "email=".$username."&password=".$password."&_csrf=".$token; echo $token; //debug info curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie); curl_setopt($ch, CURLOPT_POSTFIELDS, $postinfo); $html = curl_exec($ch); print($html); if (curl_errno($ch)) print curl_error($ch); curl_close($ch); 

Символ CSRF разграничен для каждой сессии. Прочитайте первый комментарий ot yor question (комментарий @walkingRed) (комментарий удален – токен CURL CSRF – это решение). Есть решение вашей проблемы.

Вы должны начать сеанс на другом веб-сайте, и после этого вы можете получить правильный токен csrf.

И важно использовать файлы cookie с каждым запросом, чтобы определить, что ваш внешний запрос всегда находится в одном сеансе.

Пример:

Вы делаете первый запрос, чтобы захватить токен CSRF. На внешнем веб-сайте был запущен новый сеанс для вашего запроса и сгенерирован токен csrf.

Затем вы делаете запрос anohter – но без использования файлов cookie – для этого reuqest снова начал новый сеанс и снова создал новый токен csrf для этого нового сеанса.