Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

模拟新浪微博登录:从原理分析到实现

$
0
0

在这篇文章,将继续介绍模拟登录。与之前不一样的是,这次选择的对象是新浪微博,难度稍微提升了点,好在以往的许多码友们都留有许多经验贴,经过几番斟酌,微博的模拟登录算是实现了。这两天还在研究如何高性能地爬取微博数据,业余之际乘着还有点记忆,索性将先前的小实验加工成文,算是一份小结吧。下面来看看整个实验过程。

开发工具

一如既往,笔者使用的还是之前的工具,如下:

windows 7 + python 2.75

Chrome + Fiddler

微博登录请求过程分析

新浪微博的登录有多个URL链接,笔者在实验的时候试了两个,这两个都是新浪通行证登录页面,都是不需要验证码的。一个是 【http://login.sina.com.cn】,另一个是 【https://login.sina.com.cn/signup/signin.php?entry=sso】。两个URL虽然很大部分相同,登录过程中仅仅是传递参数不一样。第一个URL传递的过程对“password”进行了加密,而第二个没有加密,所以如果使用第二个URL进行模拟登录,就简单多了。在这里,笔者决定选择使用第一种方式进行分析,下面来看详细过程。

请求登录过程可归纳为三部分

1.请求登录login.php页面前的参数预获取

2.请求登录login.php页面时的参数分析

3.提交POST请求时的参数构造

Step 1:GET方式请求prelogin.php页面

在模拟登录之前,先观察浏览器登录过程中Fiddler抓到的包,在/sso/login.php打开之前会先使用“GET”方式请求“/sso/prelogin.php”,请求的URL为:【https://login.sina.com.cn/sso/prelogin.php?entry=account&callback=sinaSSOController.preloginCallBack&su=bGl1ZGl3ZWkxOCU0MHNpbmEuY29t&rsakt=mod&client=ssologin.js(v1.4.15)】,可以看看下面这张图:


模拟新浪微博登录:从原理分析到实现

在Fiddler中,可以点击“Preview”查看具体详情,也可以直接将Request URL复制到浏览器上查看,效果图如下:


模拟新浪微博登录:从原理分析到实现

可以看出,这是一个json数据,并且携带了几个参数,我们关心的有以下四个:

servertime

nonce

pubkey

rsakv

说明一下,之所以认为这几个参数比较重要,那是因为后面对“password”的加密需要用到,对其他参数没有提及的原因是在提交POST时其它的参数并没有用到。好了,为了进行进一步探索,我们从Fiddler的结果可以看出,接下来到了“/sso/login.php”。

Step 2:POST方式请求login.php页面

从这里开始,就进行“login.php”页面的请求分析了(详细的Request URL:【https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)】,后面的时间戳可省略)。点击查看详情,结果图如下:


模拟新浪微博登录:从原理分析到实现

可以发现/sso/login.php页面有如下参数(From Data):

cdult:3
domain:sina.com.cn
encoding:UTF-8
entry:account
from:
gateway:1
nonce:AFE3O9
pagerefer:http://login.sina.com.cn/sso/logout.php
prelt:41
pwencode:rsa2
returntype:TEXT
rsakv:1330428213
savestate:30
servertime:1478568922
service:sso
sp:password
sr:1366*768
su:username
useticket:0
vsnf:1

到了这里,我们大概可以知道我们需要哪些参数了。在From Data 参数列表中,需要我们指定的参数有下面几个:

nonce

sp:加密后的密码

su:加密后的用户名

对于参数“nonce”、“servertime”、“rsakv”,都可以从第一步中的“prelogin.php” 中直接获取,而“sp”和“su”则是经过加密后的字符串值,至于具体的加密规则,我们下面通过查看源码分析得出。

Step 3:探索加密规则

首先看看请求“/sso/prelogin.php”的具体情况,看到“client”为“ssologin.js”,见下图:


模拟新浪微博登录:从原理分析到实现

然后我们到登录页面https://login.sina.com.cn中查看源码【view-source:https://login.sina.com.cn/】并搜索“ssllogin.js”,接着点击进入ssologin.js文件,这时我们可在文件中搜索“username”字符串,找到与“username”相应的加密部分(需仔细查看+揣测),接着搜索“password”,找到“password”的加密部分,最后分析出“username”和“password”的加密规则。加密部分的代码如下图:


模拟新浪微博登录:从原理分析到实现

加密用户名的代码:

1
request.su=sinaSSOEncoder.base64.encode(urlencode(username));

加密密码的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if((me.loginType&rsa)&&me.servertime&&sinaSSOEncoder&&sinaSSOEncoder.RSAKey){
request.servertime=me.servertime;
request.nonce=me.nonce;
request.pwencode="rsa2";
request.rsakv=me.rsakv;
varRSAKey=newsinaSSOEncoder.RSAKey();
RSAKey.setPublic(me.rsaPubkey,"10001");
password=RSAKey.encrypt([me.servertime,me.nonce].join("\t")+"\n"+password)
}else{
if((me.loginType&wsse)&&me.servertime&&sinaSSOEncoder&&sinaSSOEncoder.hex_sha1){
request.servertime=me.servertime;
request.nonce=me.nonce;
request.pwencode="wsse";
password=sinaSSOEncoder.hex_sha1(""+sinaSSOEncoder.hex_sha1(sinaSSOEncoder.hex_sha1(password))+me.servertime+me.nonce)
}
}

微博对于“username”的加密规则比较单一,使用的是“Base64”加密算法,而对“password”的加密规则比较复杂,虽然使用的是“RSA2”(python中需要使用pip install rsa 安装rsa模块),但加密的逻辑比较多。根据上面的代码,可以看出“password”加密是这样的一个过程:首先创建一个“rsa”公钥,公钥的两个参数都是固定值,第一个参数是登录过程中“prelogin.php”中的“pubkey”,第二个参数是加密的“js”文件中指定的“10001”(这两个值需要先从16进制转换成10进制,把“10001”转成十进制为“65537”)。最后再加入“servertime”和“nonce”进行进一步加密。

经过上面的分析之后,发起“POST”请求时的“post_data”基本上已经全部可以得到了,接下来就跟模拟登录其它网站类似了,可以使用“request”,也可以使用“urllib2”。下面来看详细代码部分。

源码实现

Github源码链接:https://github.com/csuldw/WSpider/tree/master/SinaLogin,源码

包括下列文件:

dataEncode.py:用于对提交POST请求的数据进行编码处理

Logger.py:用于打印log

SinaSpider.py:用于爬取sina微博数据的文件(主文件)

为了方便扩展,笔者将代码进行了封装,所以看起来代码量比较多,不过个人觉得可读性还是比较良好,算是凑合吧。

1.dataEncode.py 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#-*-coding:utf-8-*-
"""
CreatedonTueNov0810:14:382016
@author:liudiwei
"""
importbase64
importrsa
importbinascii
importrequests
importjson
importre
#使用base64对用户名进行编码
defencode_username(username):
returnbase64.encodestring(username)[:-1]
#使用rsa2对password进行编码
defencode_password(password,servertime,nonce,pubkey):
rsaPubkey=int(pubkey,16)
RSAKey=rsa.PublicKey(rsaPubkey,65537)#创建公钥
codeStr=str(servertime)+'\t'+str(nonce)+'\n'+str(password)#根据js拼接方式构造明文
pwd=rsa.encrypt(codeStr,RSAKey)#使用rsa进行加密
returnbinascii.b2a_hex(pwd)#将加密信息转换为16进制。
#读取preinfo.php,获取servertime,nonce,pubkey,rsakv四个参数值
defget_prelogin_info():
url=r'http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&client=ssologin.js(v1.4.18)'
html=requests.get(url).text
jsonStr=re.findall(r'\((\{.*?\})\)',html)[0]
data=json.loads(jsonStr)
servertime=data["servertime"]
nonce=data["nonce"]
pubkey=data["pubkey"]
rsakv=data["rsakv"]
returnservertime,nonce,pubkey,rsakv
#根据Fiddler抓取的数据,构造post_data
defencode_post_data(username,password,servertime,nonce,pubkey,rsakv):
su=encode_username(username)
sp=encode_password(password,servertime,nonce,pubkey)
#用于登录到http://login.sina.com.cn
post_data={
"cdult":"3",
"domain":"sina.com.cn",
"encoding":"UTF-8",
"entry":"account",
"from":"",
"gateway":"1",
"nonce":nonce,
"pagerefer":"http://login.sina.com.cn/sso/logout.php",
"prelt":"41",
"pwenco

Viewing all articles
Browse latest Browse all 12749

Trending Articles