为什么使用PHP/cURL登录远程网站会引发400错误?
我正在尝试使用cURL编写一个PHP脚本,最终将在一个网站上运行一系列测试来检查内容,但是我似乎无法通过实际的部分登录 这是我目前正在尝试的代码:为什么使用PHP/cURL登录远程网站会引发400错误?,php,curl,Php,Curl,我正在尝试使用cURL编写一个PHP脚本,最终将在一个网站上运行一系列测试来检查内容,但是我似乎无法通过实际的部分登录 这是我目前正在尝试的代码: function loginCurl() { $url = "https://mywebsite.com/main/login"; $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $login_page = curl_exec
function loginCurl() {
$url = "https://mywebsite.com/main/login";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$login_page = curl_exec($ch);
$csrf = preg_replace("/_csrf\"\svalue=\"/", "", substr($login_page, strpos($login_page, "_csrf"), 70));
$username = "myEmail@mywebsite.com";
$password = "abcde12345";
$post_data = http_build_query(array(
'_csrf' => $csrf,
'LoginForm' => array (
'username' => $username,
'password' => $password,
'rememberMe' => 1
)
));
$HttpRequestHeaders = array(
"Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language:en-US,en;q=0.8",
"Cache-Control:max-age=0",
"Connection:keep-alive",
"Referer:https://mywebsite.com/main/login",
"Upgrade-Insecure-Requests:1"
);
curl_setopt($ch, CURLOPT_URL, "https://mywebsite.com/main/login");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_ENCODING, '');
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
curl_setopt($ch, CURLOPT_HTTPHEADER, $HttpRequestHeaders);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
$home_page = curl_exec($ch);
curl_close($ch);
return $home_page;
}
然而,每次我运行这段代码时,服务器都会响应一个HTTP400错误,尽管就我所见,我的请求并没有格式错误
当我在Chrome中打开开发者视图登录到实际的网站时,我可以打开网络下的登录页面,看到表单字段中传递的所有数据,这只是我代码中的5个内容。我不完全清楚为什么它会发送两次“rememberMe”复选框,但不管我发送多少次,它都会失败
这里的问题是,尽管现在我的表单数据和请求头与手动登录真实站点时的表单数据和请求头相同,但仍然会出现400错误
我想我真正的问题会分为几个不同的部分:
Request headers:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/ *;q=0.8
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:212
Content-Type:application/x-www-form-urlencoded
Cookie:_csrf=1c43726b4d2c2298b2667f1c9b47d420ee594f2de08a9ce928ee155b174c624aa%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%22niY-LESiKNwZkfg7mclgTuBPDJeLACz2%22%3B%7D; PHPSESSID=itnbbfiph1gj2p9movpmi9pmb7
Host:mywebsite.com
Origin:https://mywebsite.com
Referer:https://mywebsite.com/main/login
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Form Data:
_csrf:Z0owR2dpVXQJI2lqKywGHSwERx0MDzJDCilcIDMcFyQjAFULJiovRg==
LoginForm[username]:myEmail@mywebsite.com
LoginForm[password]:abcdefg12345
LoginForm[rememberMe]:0
LoginForm[rememberMe]:1
这是一个开发者视图,只有当你打开它时它才会跟踪
这是它为网页的实际请求记录的内容:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/ *;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:_csrf=1c43726b4d2c2298b2667f1c9b47d420ee594f2de08a9ce928ee155b174c624aa%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%22niY-LESiKNwZkfg7mclgTuBPDJeLACz2%22%3B%7D; PHPSESSID=i4ppm1ggcq1cq6hkvilesggr10; _identity=2ca675db2d582db9f7ab8761cc0a07a14e2e2dece90386b11392b270637b0559a%3A2%3A%7Bi%3A0%3Bs%3A9%3A%22_identity%22%3Bi%3A1%3Bs%3A19%3A%22%5B1267%2Cnull%2C2592000%5D%22%3B%7D
Host:mywebsite.com
Referer:https://mywebsite.com/main/login
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
这是包含csrf标记的sites HTML中的标记,当我回送csrf时,它会按原样显示。我不相信有解析错误,但是它在HTTP响应头中的显示方式不同,这对我来说很奇怪
<input type="hidden" name="_csrf" value="T25ZVmZGZi4hBwB7KgM1RwQgLgwNIAEZIg01MTIzJH4LJDwaJwUcHA==">
我希望有人能帮我解决这个问题,我已经做了几天了 你犯了几个错误 您的post_数据没有正确编码,
[
应该是%5B
,而]
应该是%5D
,如
”&LoginForm%5Busername%5D=“。urlencode($username)
此外,您正在以相同的形式将LoginForm[rememberMe]重新定义为0
和1
,这肯定是不合法的
但是,与其自己制作编码字符串(这很难看,而且(正如您刚刚证明的那样)容易出错,不如让http\u build\u query
为您这样做:
$post_data = http_build_query ( array (
'_csrf' => $csrf,
'LoginForm' => array (
'username' => $username,
'password' => $password,
'rememberMe' => 1
)
) );
您说您“接受编码:gzip、deflate、sdch、br”
,但如果服务器决定使用这些编码,您没有提供任何代码来处理这些编码,并且您的loginCurl()函数无法告诉调用方服务器决定使用哪种编码。。最好的处理方法是自动为您提供curl句柄编码。不要自己发送accept encoding
标题,而是将CURLOPT_encoding
设置为emptstring'
,如果服务器决定使用编码,curl将自动accept encoding:
-并自动解码
您可以手动设置主机:头,不要这样做,让curl为您设置,就像curl\u init
为您所做的那样(或者使用CURLOPT\u URL
),此外,您可能希望使用CURLOPT\u USERAGENT
而不是自己设置USERAGENT头(如果手动设置,很容易忘记)
此外,有些页面可能会检测到您伪造了推荐人
标题,您可能只需设置CURLOPT_AUTOREFERER,并向您想要推荐人的url发出GET请求,而不是伪造推荐人标题:p
问题远程登录网站是否有比使用cURL更好的方法。据我所知,这是最好的方法。
-如果网站没有特定的api,那么根据我的经验,(lib)cURL是像浏览器一样登录的最好方法
问题如果这是最好的方法,那么有没有比查看开发者视图中的表单数据更好的方法来准确地告诉我登录页面时发送的内容呢。
-idk,但是99%的时间,chrome开发者工具对我来说都很好。有时,我不得不求助于Fiddler代理
或ReDox数据包编辑器
,当我想分析非浏览器应用程序时
问题<代码>如果没有比我现在做的更好的方法,是否有可能该站点错误地抛出了400个错误,而它真的应该是其他错误?如果是这样,我将如何克服这个错误?
-好吧,正如我上面所说的,你在这里做错了,但是当它在浏览器中工作,而在curl中不工作时,诀窍是将curl的请求与chrome的请求进行比较,并系统地消除基于curl的请求和基于浏览器的请求之间的每一个差异,直到它们实现为止e完全相等,并重试每一步。FiddlerProxy和netcat(在Linux中很常见,在windows中需要Cygwin)在这里派上了用场
编辑9001:
PS,查看您提供的测试数据,看起来像您的preg
$csrf=preg\u replace(…
code无法正确提取CSRF令牌。您的curl CSRFz0OWR2DPVXQJI2LKYWGHSWERX0MDZJDCILCIDMCFYQJAFULJIOVRG==
与记录的CSRF1C43726B4D2C22982667F1C9B47D420EE594F2DE08A9CE928EEB174C624AA%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22%3Bi%3A1%3A%3Bs%3A32%3A%3A%3A%3A%jefglacz2%22%3B%7D
如果你犯了一些错误,你就不应该