QQ第三方网站授权登陆深入分析及cookie的高级运用

前言


现如今越来越多的网站采用QQ或微信作为用户的一种快速登陆方式。随着互联网技术的发展,对自动化登陆的要求也随之产生,那么本文就由QQ出发,深入分析下QQ的授权流程,并如何实现自动化登陆。关键代码不分享,仅供参考学习。

首先简单看看QQ第三方网站授权登陆的流程图

简单原理


接触过自动登陆QQ的朋友都知道,最难的就是过验证码,可以参考目前网上例如使用python或者接码平台等方式,但本文的简化这些步骤,服务器的IP多登陆几次成为常用IP后登陆就不需要验证。当然,本文的重点不是QQ登陆,而是如何授权第三方网站。

1、获取需授权的QQ账号信息


  • 如何实现加密验证

使用Fiddler抓包分析登陆流程,重点要解决p参数的加密过程。按F12调试发现以下函数

可看出共使用了TEA、RSA、BASE64一共3种方式混合加密,并且这3种加密函数全由原生JS实现,以上函数使用PHP重写后:

    //16进制字符串转字符串
    public function hexToStr($hex){
    	$str="";
    	$strlen=strlen($hex);
    	for($i=0;$i<$strlen;$i+=2)
    		$str.=chr(hexdec($hex[$i].$hex[$i+1]));
    	return $str;
    } 
    //QQ账号转16进制字符串
    public function QQToHex($str){
        $str=dechex($str);
        for($i = strlen($str);$i < 16; $i ++){
            $str = "0".$str;
        }
        return $str;
    }     
    //QQ登录验证加密函数参数:QQ密码 账号 验证码 是否加密
    public function QQLoginEncrypt($p,$u,$c,$md5="") {
        $hexu= $this->QQToHex($u);// 字符串转hex加密
        $md5p= md5($p);
        $clen= "000".strlen($c);
        $binc= bin2hex(strtoupper($c));
        $key = strtoupper(md5($this->hexToStr($md5p.$hexu)));// MD5加密
        $data= strtoupper($md5p).$hexu.$clen.$binc;
        $EnStr = TEAandRSA($key,$data);//TEA加密 与 RSA加密
        $EnP=base64_encode($this->hexToStr($EnStr)); //BASE64加密
        $EnP=str_replace('/','-',$EnP);
        $EnP=str_replace('+','*',$EnP);
        $EnP=str_replace('=','_',$EnP);
        return $EnP;
    }

其中TEA和RSA的加密因为嫌麻烦就直接用PHP运行js代码了(需要安装v8js扩展)。以下函数的JS代码也是在c_login_2.js中提取的。

  • 模拟用户QQ登陆


    //判断QQ登录方式
    public function CheckQQLoginType(){
        $header=array(
            "Host: ssl.ptlogin2.qq.com",
            "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0",
            "Accept: */*",
            "Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
            "Accept-Encoding: gzip, deflate, br",
            "Connection: keep-alive",
            "Referer: https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=716027609&daid=383&style=33&login_text=%E6%8E%88%E6%9D%83%E5%B9%B6%E7%99%BB%E5%BD%95&hide_title_bar=1&hide_border=1&target=self&s_url=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&pt_3rd_aid=101470313&pt_feedback_link=https%3A%2F%2Fsupport.qq.com%2Fproducts%2F77942%3FcustomInfo%3D.appid101470313",
            "Cookie: "
        );
        $url="https://ssl.ptlogin2.qq.com/check?regmaster=&pt_tea=2&pt_vcode=1&uin=".$this->qqnum."&appid=716027609&js_ver=20032614&js_type=1&login_sig=&u1=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&r=0.101003".time()."&pt_uistyle=40";
        $body = $this->curl($url,"","",$header,0);
        //ptui_checkVC('0','!FKE','\x00\x00\x00\x00\x2e\x35\x91\x80','258ae60419e861ea579886ca18f76983b2e77ddf7e870e93b0bd70ab14a6e7637752aafb1de9925d594a7ef70eb3ae2e4e89fda3e181cd63','2', 'uIYUkvs2dy7*m*KdoG6jZu7a6lhs8crUEb8shkSpPT097PMKmhLKdlp-tx4opH1-')
        $data = str_replace("'","",$this->pregjson($body,"ptui_checkVC"));
        $data = str_replace(" ","",$data);
        $data = explode(",",$data);
        return $data;
    }
    //登录QQ账号
    public function LoginQQAccount($data){
        $header=array(
            "Host: ssl.ptlogin2.qq.com",
            "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0",
            "Accept: */*",
            "Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
            "Accept-Encoding: gzip, deflate, br",
            "Connection: keep-alive",
            "Referer: https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=716027609&daid=383&style=33&login_text=%E6%8E%88%E6%9D%83%E5%B9%B6%E7%99%BB%E5%BD%95&hide_title_bar=1&hide_border=1&target=self&s_url=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&pt_3rd_aid=101470313&pt_feedback_link=https%3A%2F%2Fsupport.qq.com%2Fproducts%2F77942%3FcustomInfo%3D.appid101470313",
            "Cookie: ".$data[8]."; confirmuin=".$data[0]."; ptdrvs=".$data[5]."; ptvfsession=".$data[3]."; ptui_loginuin=".$data[6]
        );
        $url="https://ssl.ptlogin2.qq.com/login?u=".$data[6]."&verifycode=".$data[1]."&pt_vcode_v1=0&pt_verifysession_v1=".$data[3]."&p=".$data[7]."&pt_randsalt=".$data[4]."&u1=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=2-0-1590368126499&js_ver=20032614&js_type=1&login_sig=&pt_uistyle=40&aid=716027609&daid=383&pt_3rd_aid=101470313&ptdrvs=".$data[5]."&";
        $body = $this->curl($url,"","",$header,1);
        //ptuiCB('0','0','https://ssl.ptlogin2.graph.qq.com/check_sig?pttype=1&uin=775262592&service=login&nodirect=0&ptsigx=9a2a261166dec9d5feb5413d69910a3d7d2b7dd7de9dce096515c193aa68f5bbaef54e72992f558370ade62dbf7db87129e8ce91cda5fd9d7ec34b3b4a4a4a59&s_url=https%3A%2F%2Fgraph.qq.com%2Foauth2.0%2Flogin_jump&f_url=&ptlang=2052&ptredirect=100&aid=716027609&daid=383&j_later=0&low_login_hour=0&regmaster=0&pt_login_type=1&pt_aid=0&pt_aaid=0&pt_light=0&pt_3rd_aid=101470313','0','登录成功!', '皮皮华')
        // return $body;
        $data = str_replace("'","",$this->pregjson($body,"ptuiCB"));
        $data = str_replace(" ","",$data);
        $data = explode(",",$data);
        return $data;
    }
    //获取QQ登录成功后的p_skey
    public function QQLoginGetPskey($url){
        $json=$this->curl($url,"","",array(),1);
        list($header, $body) = explode("\r\n\r\n", $json,2);
        preg_match('/Set-Cookie: p_skey=(.*);(.*)graph.qq.com/iU',$header,$str); //正则匹配
        $data = "pt_login_type=1; p_skey=".$str[1];
        $this->g_tk=$this->getGTK($str[1]);
        if(strlen($str[1]) < 1){
            $this->code= 202;
            $this->msg="获取登录p_skey的Cookie值失败";
            return $json;
        }
        preg_match('/Set-Cookie: p_uin=(.*);(.*)graph.qq.com/iU',$header,$str); //正则匹配
        $data= $data . "; p_uin=" .$str[1];
        if(strlen($str[1]) < 1){
            $this->code= 202;
            $this->msg="获取登录p_uin的Cookie值失败";
            return $json;
        }
        preg_match('/Set-Cookie: pt4_token=(.*);(.*)graph.qq.com/iU',$header,$str); //正则匹配
        $data= $data . "; pt4_token=" .$str[1];
        if(strlen($str[1]) < 1){
            $this->code= 202;
            $this->msg="获取取登录pt4_token的Cookie值失败";
            return $json;
        }
        $this->code= 200;
        $this->msg="获取登录Cookie值成功";
        $this->cookie = $data;
        file_put_contents("authqq.json",json_encode($data));
        return $json;
    }
    //重新获取QQ授权Cookie
    public function GetAuthCookie(){
        $data = $this->CheckQQLoginType();
        if($data[0] == "0"){//免密登录
            $data[6] = $this->qqnum;
            $data[7] = $this->QQLoginEncrypt($this->qqpwd,$this->qqnum,$data[1]);//P参数加密
            $logindata = $this->LoginQQAccount($data);
            if($logindata[4]=="登录成功!"){
                $this->QQLoginGetPskey($logindata[2]);
            }
        }
        return $data;
    }

2、怎样授权第三方网站并拿到第三方网站的cookie


同样使用Fiddler抓包分析登陆流程,整个过程分3步走。

    //获取第三方网站Cookie
    public function GetSiteCookie($sitename){
        $state= "";
        if(strlen($this->site[$sitename]["loginurl"]) > 1){
            $state = $this->GetState($sitename);//获取state
        }
        $url = $this->authorize($sitename,$state);//授权第三方网页
        if($this->code == 200){
            return $this->GetUrlCookie($sitename,$url);//获取回调网页Cookie
        }
    }

1)获取state

某些网站在接入Oauth2.0时并没有做state验证,所以也不需要此步骤。以下以网易云音乐为例。

        "pph_music163" => array(
                    "name" => "网易云音乐",//网站名称
                    "loginurl" => "https://music.163.com/api/sns/authorize?snsType=5&clientType=web2&callbackType=Login&forcelogin=true",//State获取url
                    "redirect_uri" => "https%3A%2F%2Fmusic.163.com%2Fback%2Fqq",//回调地址
                    "client_id" => "100495085",//网易云网站对应的ID
                    "cookielist" => array("MUSIC_U" => ""),//需要获取的Cookie值
                    "cookieignorelist" => array(),
                    "cookieTime" => 1267200,//24*60*60*15-8*60*60, Cookie有效时长,单位秒
                    "cookieEndTime" => 0  //cookie到期时间
                ),

通过Fiddler找到网易云音乐对应获取state的url:https://music.163.com/api/sns/authorize?snsType=5&clientType=web2&callbackType=Login&forcelogin=true

模拟请求该链接后通过正则匹配获取state的值。

2)授权第三方网页

通过POST请求https://graph.qq.com/oauth2.0/authorize传入最重要的client_id、redirect_uri、state、g_tk这4个参数,其中g_tk由p_skey计算得出。如果授权成功则会返回授权成功后的回调url。

3)获取回调网页Cookie

模拟请求上一步获取到的回调url即可获取到对应网站的cookie信息。

总结

通过以上流程即可全自动化的实现登录,并且可以在此基础上增加cookie到期时间判断,实现定时更新第三方网站的cookie。

以下为PHP版完整的第三方授权类,

本文仅供思路参考,严禁用于非法用途,转载请注明出处。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值