以pay.qq.com查询QQ账号Q币信息为例,了解一下网站的二维码登陆大致是如何实现的
首先打开腾讯pay.qq.com主页上的登陆就可以获取到二维码了,使用浏览器的F12分析请求过程
发现通过打开的https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=11000101&target=self&style=40&s_url=https://pay.qq.com/ipay/login-proxy.html可以获取到cookies,这个url就先记下来
继续往下,打开下面的url,响应回来的就是二维码了
那这些请求的参数是如何得到的呢,多次请求分析发现只有t是随机变化的,那就给个随机数吧
参数t的python生成方式(python生成的随机数多一位)
import random
a=str(random.random())
print(a)
print(a[:-1])
当用手机扫了二维码之后,会发现一直请求一个地址,而返回的内容就是判定二维码是否过期的结果。但是请求的url随二维码的更新而变化的
获取是否过期(通过请求的url发现如下规律)
https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken=1300613866&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1514654333018&js_ver=10233&js_type=1&login_sig=pGo5iOnV6O*DY3BgsPM22zAvlWCnVl48PPjrmWIJtQKMHpvYCoWpavmP1JcdWn6g&pt_uistyle=40&aid=11000101&
https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken=1641999182&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1514655242011&js_ver=10233&js_type=1&login_sig=pGo5iOnV6O*DY3BgsPM22zAvlWCnVl48PPjrmWIJtQKMHpvYCoWpavmP1JcdWn6g&pt_uistyle=40&aid=11000101&
https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken=1460309603&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1514656150867&js_ver=10233&js_type=1&login_sig=pGo5iOnV6O*DY3BgsPM22zAvlWCnVl48PPjrmWIJtQKMHpvYCoWpavmP1JcdWn6g&pt_uistyle=40&aid=11000101&
这些url返回结果如下这样的形式
ptuiCB('66','0','','0','二维码未失效。(2079330212)', '')
那么,这次的url所附带的参数更多了,究竟是如何生成的,由于没有学习过JavaScript,但是猜想这种交互式的网页一定有js控制的。
打开请求主页中所有的js链接,文件中都没有相关信息,于是重头分析请求过程,发现请求了一个url里面返回大量函数,里面有且仅有一个ptqrtoken变量
https://imgcache.qq.com/ptlogin/ver/10233/js/c_login_2.js?max_age=604800&ptui_identifier=000E010D989AA31CE07BA6E98F56BC76012729B221D540BFF0DE375CAC8A
这个url返回的代码里面找到getSubmitUrl函数如下:
三个参数ptqrtoken、action、login_sig。两个参数都在函数中说明了,login_sig同样在这段返回的代码里面,事实上就是cookies里面的pt_login_sig
于是乎可以试着构造一个这样的url,判断二维码是否有效。响应的代码里面跟三个参数有关的代码如下
函数的具体实现—ptqrtoken生成
hash33:function(t){
for(var e=0,i=0,n=t.length;i<n;++i)
e+=(e<<5)+t.charCodeAt(i);
return 2147483647&e
}
函数的具体实现—action生成
,pt.plogin={account:"",at_account:"",uin:"",salt:"",checkState:!1,lastCheckAccount:"",needVc:!1,vcFlag:!1,ckNum:{},action:[0,0],passwordErrorNum:1,isIpad:!1,seller_id:703010802
action.join(“-”)+”-”+(new Date-0)
函数的具体实现—login_sig生成(这个是http响应时返回的)
login_sig=pt.ptui.login.sig
用javascript测试下实现函数功能的代码(不懂js所以先试下运行出来是什么结果)
1、ptqrtoken
<script type="text/javascript">
document.write(isNaN(123)+ "<br />")
function test(t){
for(var e=0,i=0,n=t.length;i<n;++i)
e+=(e<<5)+t.charCodeAt(i);
return 2147483647&e;
}
document.write(test("l5ReOk*DhvMzPYYjfqWzkYjwSs52j6lzw1Oy6SaMsUNywLorCwuRuP8TbGfzSf*a"))
</script>
2、action
document.write(new Date-0);
document.write("<br/>")
var t=new Date()
action=[0,0]
document.write(action.join("-")+"-"+t.getTime())
知道了逻辑,用python重写javascript的函数来实现同样功能
ptqrtoken的生成
t1="l5ReOk*DhvMzPYYjfqWzkYjwSs52j6lzw1Oy6SaMsUNywLorCwuRuP8TbGfzSf*a"
def test(t):
i=0
e=0
n=len(t)
fori in range(n):
e=e+(e<<5)
e=e+ord(t[i])
print(e)
print(2147483647&e)
test(t1)
action的生成就只是一个时间函数
import time
print(int(time.time()*1000))
继续往下分析连续请求该Url响应用户的扫码登陆状态,发现扫码成功后,也会返回cookies
带着cookies请求个人账户主页https://my.pay.qq.com/account/index.shtml?aid=pay.index.header.acct&ADTAG=pay.index.header.acc
发现返回的内容还是没有Q币的信息,说明内容还是由javascript动态生成
返回的js里面是没有Q币信息的
继续分析下面请求的url
发现了这个 https://my.pay.qq.com/cgi-bin/personal/balance_query_sortflow.cgi?items=qd,qb&_=0.9267836264725212
于是返回的json,qb_balance就是个人账户的Q币
import requests
import time
import random
def ptqrtoken_str(qrsig): #三个函数就是url的三个参数生成
i=0
e=0
n=len(qrsig)
for i in range(n):
e=e+(e<<5)
e=e+ord(qrsig[i])
e=2147483647&e
return e
def action_str():
a=int(time.time()*1000)
b='0-0-'+str(a)
return b
def pt_loginsig_str(ckiesget):
st=ckiesget.headers['Set-Cookie']
return st[st.find('pt_login_sig=')+13:st.find('pt_login_sig=')+77]
url_getcookies="https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=11000101&target=self&style=40&s_url=https://pay.qq.com/ipay/login-proxy.html"
s=requests.session() #requests的session可以自动管理cookies
ckget=s.get(url_getcookies)
t=str(random.random())
url_getqr="https://ssl.ptlogin2.qq.com/ptqrshow?appid=11000101&e=2&l=M&s=3&d=72&v=4&t="+t[:-1]+"&pt_3rd_aid=0"
qrget=s.get(url_getqr)
f=open('tmp.png','wb') #将二维码保存为图片手动打开来扫码^_^
f.write(qrget.content)
f.close()
for i in range(1,7): #简单的循环返回二维码是否失效,循环结束前扫码就获得了cookies
time.sleep(3)
qrsig=qrget.headers['Set-Cookie'].split(';')[0][6:]
url_check_timeout="https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken="+str(ptqrtoken_str(qrsig))+"&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action="+action_str()+"&js_ver=10233&js_type=1&login_sig="+pt_loginsig_str(ckget)+"&pt_uistyle=40&aid=11000101&"
timeoutget=s.get(url_check_timeout)
print(timeoutget.status_code)
print('----------------text---------------')
print(timeoutget.text)
print(timeoutget.headers)
happy3=s.get("https://my.pay.qq.com/cgi-bin/personal/balance_query_sortflow.cgi?items=qd,qb&_="+str(random.random()))
print(happy3.text)