$ch = curl_init();
$url = "https://segmentfault.com/api/user/login?_=fb8eb567a6f2a4ed7d28a1ac62c0d018";
$data = array(
'mail' => ***
'password' => ***
);
foreach ($data as $key => $value){
$postfields .= urlencode($key) . '=' . urlencode($value) . '&';
}
$postfields = rtrim($postfields, '&');
$headers = array(
'Accept:*/*',
'Accept-Encoding:gzip, deflate',
'Accept-Language:zh-CN,zh;q=0.8',
'Connection:keep-alive',
'Content-Length:49',
'Content-Type:application/x-www-form-urlencoded; charset=UTF-8',
'Cookie:mp_18fe57584af9659dea732cf41c1c0416_mixpanel=%7B%22distinct_id%22%3A%20%22153c6c3ec0c91-04fd9c038-12771e2d-1fa400-153c6c3ec0d18a%22%2C%22%24initial_referrer%22%3A%20%22%24direct%22%2C%22%24initial_referring_domain%22%3A%20%22%24direct%22%7D; PHPSESSID=web2~dom8lkdgosec57oljs98g2m8k0; _gat=1; Hm_lvt_e23800c454aa573c0ccb16b52665ac26=1463986883,1464937399,1465290769,1465713371; Hm_lpvt_e23800c454aa573c0ccb16b52665ac26=1465717067; _ga=GA1.2.1469164019.1455850659',
'Host:segmentfault.com',
'Origin:https://segmentfault.com',
'Referer:https://segmentfault.com/',
'User-Agent:Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36',
'X-Requested-With:XMLHttpRequest',
);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
curl_setopt($ch, CURLOPT_ENCODING, "");
$result = curl_exec($ch);
curl_close($ch);
var_dump($result);
返回结果说我用户或密码错误? 账号密码是正确的。
前言
本文来自我在segmentfault上的回答,我纪录了其中精彩的部分到本博客。
大致意思是模拟登陆segmentfault.com,一时手痒,本文将带领大家一起实现这个操作。
<!-- more -->
解析
这个问题问的非常好,但可惜的是大家的回复都是纸上谈兵未经探讨,最前最高票的回答的竟然说让下抓包工具,简直可笑啊,chrome下F12直接就可以看到账号密码是明文发送的何必还要抓包?另外的题主的http头就是从chrome下复制的。
根据竟然我判断你的问题的原因是发送了过多的http头,其中
Content-Length
是明显有问题的,这个代表内容长度,你这次抓包是49,但下次换个账号密码可就真不一定了。比如,如果账号密码过长,可能就会导致截断,那么无论如何都会提示密码错误的(因为只发送了一部分的密码过去)。方案
事实上为了探究这个有意思的问题,我专门动手做一个有意思的实验。
这里就用个最简单的脚本语言
node.js
中的ajax
模型来重新构建操作过程。分析
我们先去登陆页--源码页去大致看一下,其中
这个跨域请求加载js脚本,看名字应该是和登陆有关的,我们这边使用尝试访问下,结果不用想,一篇乱糟糟的。
根据命名规范,我们猜测压缩前的名字可能就是叫
login.js
,我们看下他删除了没有,我们尝试访问https://dfnjy7g2qaazm.cloudfront.net/v-575e20ec/user/script/login.js
,嗯哼还在,看来他们的发布人员可能不是处女座的。那好我们往下看下这里:
代码非常简单,我们知道了请求结果中status为0时代表登陆成功,同时我们也知道了后台执行登陆请求页是
/api/user/login
,即https://segmentfault.com/api/user/login
,我们访问一下,嗯404。这说明了服务端验证了输入,并判断我们的请求不符合正常逻辑。下面我们开始伪造请求头。请求头
我们用类似chrome的现代化浏览器,正常访问
https://segmentfault.com/user/login
,按下F12,选择network
面板开始监控请求,然后我们随意填写账号密码,点击登陆。这个时候下面会有一条信息,我们提取其中的
Request Header
如下我们只需要同样发送这些请求到服务器上,理论上就不会有问题,同时也不会再404了。
这里面的数据中,有些不需要发的,有些是必须要发送的。
我们可以一一测试下。
调试
我们这里使用nodejs来简单写段代码测试下服务端所验证的参数。
枯燥的测试就是不断删减请求来看看服务端会不会返回404.
过程不再赘述,结果是:
querystring中的
_
必须和Cookie
中的PHPSESSID
对应。X-Requested-With
的值需要带ajax请求标志,即XMLHttpRequest
Referer
的值看来他们服务端还是蛮严格的。
源码
同时,开源在github上,地址segmentfault_loginer