PHP如何使用curl模拟登陆?

 QueenieYam任嘉明 发布于 2022-11-16 21:43
$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);


返回结果说我用户或密码错误? 账号密码是正确的。
10 个回答
  • 应该是密码在前端做了hash加密,你可以抓个包看下

    2022-11-16 21:58 回答
  • 既然是https,那为啥不加上curl的https选项

    2022-11-16 21:58 回答
  • 不错,问题具有代表性

    2022-11-16 21:58 回答
  • 之前写过一个51job的模拟登录并投递简历的demo,代码如下,可参考

    <?php
    // 首先引入zend框架(官网地址:http://www.zend.com/)
    require_once 'Zend/Loader.php';
    
    Zend_Loader::loadClass('Zend_Http_Client');
    $client  = new Zend_Http_Client();
    $client->setCookieJar();
    
    /**
     * 登录
     */
    //$client->setHeaders('Set-cookie', $response->getHeader('Set-cookie'));
    $client->setUri('http://my.51job.com/my/passport_login.php');
    $client->setMethod('POST');
    $client->setParameterPost(array(
        'from_domain'        => 'www.51job.com',
        'passport_loginName' => '*****',  // 账号
        'passport_password'  => '***'   // 密码
    ));
    $res = $client->request();
    
    /**
     * 投简历
     */
    $client->setUri('http://my.51job.com/sc/sendtwo/send_resume_new.php');
    $client->setHeaders('Host', 'my.51job.com');
    $client->setHeaders('Cookie', $res->getHeader('Set-cookie'));
    $client->setMethod('GET');
    $client->setParameterGet(array(
        'isEN'         => '0',
        'rsmid'        => '337097130',
        'deflang'      => '0',
        'coverid'      => '',
        'jsoncallback' => 'jsonp1447931687767',
        '_'            => '1447931692678',
        'jobiduni'     => '(73015544)',   //括号里面为职位id
    ));
    $rs = $client->request();
    print_r($rs);
    2022-11-16 21:58 回答
  • 至少得先保存个cookie在登录吧

    2022-11-16 21:58 回答
  • $ch = curl_init();
    $url = "https://segmentfault.com/api/user/login?_=259f90fcf626f304c69c52db1454f03e";
    
    $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-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; editor-code-detect-disabled=1; PHPSESSID=web2~oag2uol7e47i88hp6t6uqac9b0; Hm_lvt_e23800c454aa573c0ccb16b52665ac26=1465290769,1465713371,1465781816,1465866651; Hm_lpvt_e23800c454aa573c0ccb16b52665ac26=1465867161; _ga=GA1.2.1469164019.1455850659; _gat=1',
        '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_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_ENCODING, "");
    $result = curl_exec($ch);
    curl_close($ch);
    
    var_dump($result);
    2022-11-16 21:58 回答
  • 看原始http请求

    2022-11-16 21:58 回答
  • 用Charles是可以对HTTPS进行抓包的 可以参考这个http://www.tuicool.com/articles/JfEZr23
    如果密码在前端用JS进行加密的话 是可以找出来这段加密代码的 也可以找出加密算法 你就可以模拟这个算法进行加密 我之前爬中国移动的网站 也遇到这种问题

    2022-11-16 21:58 回答
  • 前段并没有加密,90%的可能出在cookie上

    给你一个建议:

    1.现访问下:https://segmentfault.com/ 拿到cookie
    2.再进行post提交
    3._这个GET参数也很重要哦

    2022-11-16 21:58 回答
  • 前言

    本文来自我在segmentfault上的回答,我纪录了其中精彩的部分到本博客。
    大致意思是模拟登陆segmentfault.com,一时手痒,本文将带领大家一起实现这个操作。

    <!-- more -->

    解析

    这个问题问的非常好,但可惜的是大家的回复都是纸上谈兵未经探讨,最前最高票的回答的竟然说让下抓包工具,简直可笑啊,chrome下F12直接就可以看到账号密码是明文发送的何必还要抓包?另外的题主的http头就是从chrome下复制的。
    根据竟然我判断你的问题的原因是发送了过多的http头,其中Content-Length是明显有问题的,这个代表内容长度,你这次抓包是49,但下次换个账号密码可就真不一定了。比如,如果账号密码过长,可能就会导致截断,那么无论如何都会提示密码错误的(因为只发送了一部分的密码过去)。

    方案

    事实上为了探究这个有意思的问题,我专门动手做一个有意思的实验。
    这里就用个最简单的脚本语言node.js中的ajax模型来重新构建操作过程。

    分析

    我们先去登陆页--源码页去大致看一下,其中

    <script crossorigin src="https://dfnjy7g2qaazm.cloudfront.net/v-575e20ec/user/script/login.min.js?1.2.1"></script>

    这个跨域请求加载js脚本,看名字应该是和登陆有关的,我们这边使用尝试访问下,结果不用想,一篇乱糟糟的。
    根据命名规范,我们猜测压缩前的名字可能就是叫login.js,我们看下他删除了没有,我们尝试访问https://dfnjy7g2qaazm.cloudfront.net/v-575e20ec/user/script/login.js,嗯哼还在,看来他们的发布人员可能不是处女座的。
    那好我们往下看下这里:

    $("form[action='/api/user/login']").submit(function() {
      var data, url;
      url = '/api/user/login';
      data = $(this).serialize();
      $.post(url, data, function(d) {
        if (!d.status) {
          return location.href = d.data;
        }
      });
      return false;
    });

    代码非常简单,我们知道了请求结果中status为0时代表登陆成功,同时我们也知道了后台执行登陆请求页是/api/user/login,即https://segmentfault.com/api/user/login,我们访问一下,嗯404。这说明了服务端验证了输入,并判断我们的请求不符合正常逻辑。下面我们开始伪造请求头。

    请求头

    我们用类似chrome的现代化浏览器,正常访问https://segmentfault.com/user/login,按下F12,选择network面板开始监控请求,然后我们随意填写账号密码,点击登陆。
    这个时候下面会有一条信息,我们提取其中的Request Header如下

    POST /api/user/login?_=93e1b923149fb56c4fd329fe95ea4001 HTTP/1.1
    Host: segmentfault.com
    Connection: keep-alive
    Content-Length: 46
    Pragma: no-cache
    Cache-Control: no-cache
    Accept: */*
    Origin: https://segmentfault.com
    X-Requested-With: XMLHttpRequest
    User-Agent: xxxx
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    DNT: 1
    Referer: https://segmentfault.com/
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4
    Cookie: PHPSESSID=web5~to8l5ovmt9t3jkb84aevuqf151; Hm_lvt_e23800c454aa573c0ccb16b52665ac26=1465799317; Hm_lpvt_e23800c454aa573c0ccb16b52665ac26=1465799317; _ga=GA1.2.915515414.1465799317; _gat=1
    

    我们只需要同样发送这些请求到服务器上,理论上就不会有问题,同时也不会再404了。
    这里面的数据中,有些不需要发的,有些是必须要发送的。
    我们可以一一测试下。

    调试

    我们这里使用nodejs来简单写段代码测试下服务端所验证的参数。
    枯燥的测试就是不断删减请求来看看服务端会不会返回404.
    过程不再赘述,结果是:

    1. querystring中的 _必须和Cookie中的PHPSESSID对应。

    2. X-Requested-With的值需要带ajax请求标志,即XMLHttpRequest

    3. Referer的值

    看来他们服务端还是蛮严格的。

    源码

    var superagent = require('superagent');
    
    
    superagent.post('https://segmentfault.com/api/user/login?_=7ef046ad4f224034d7b51655238bd870')
        .set('Referer', 'https://segmentfault.com/user/login')
        .set('X-Requested-With', 'XMLHttpRequest')
        .set('Cookie', 'PHPSESSID=web1~395mahoqliohh5kclv894ibpr3; _gat=1; _ga=GA1.2.1234754628.1465797373; Hm_lvt_e23800c454aa573c0ccb16b52665ac26=1465797373; Hm_lpvt_e23800c454aa573c0ccb16b52665ac26=1465797538')
        .send({
            mail: "xxxxxx",
            password: "xxxx"
        })
        .type('form')
        .end(function(err, res) {
            if (err || !res.ok) {
                console.log(err.status);
            } else {
                console.log('yay got ' + JSON.stringify(res.body));
            }
        });
    

    同时,开源在github上,地址segmentfault_loginer

    2022-11-16 21:58 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有