Python实现⽹站模拟登陆
⼀、实验简介
1.1 基本介绍
本实验中我们将通过分析登陆流程并使⽤ Python 实现模拟登陆到⼀个实验提供的⽹站,在实验过程中将学习并实践 Python 的⽹络编程,Python 实现模拟登陆的⽅法,使⽤ Firefox 抓包分析插件分析⽹络数据包等知识。
模拟登录可以帮助⽤户⾃动化完成很多操作,在不同场合下有不同的⽤处,⽆论是⾃动化⼀些⽇常的繁琐操作还是⽤于爬⾍都是⼀项很实⽤的技能。本课程通过 Firefox 和 Python 来实现,环境要求如下:
Python 库:urllib, urllib2, cookielib, Django
Firefox 要求:装有 live http header插件 (已提供)
1.2 知识点
本项⽬中我们将学习并实践以下知识点:
1. ⽹站登录流程分析
2. Python ⽹络编程基础
3. Firefox 抓包分析插件 Live http header
4. Python 模拟登陆实现流程
1.3 实验材料
为了节省时间,实验⽤到的材料已经提前制作完成,可以按照材料清单中给出的链接下载。
实验⽹站源码:
labfile.oss.aliyuncs/courses/640/mysite.zip
FireFox抓包插件:
labfile.oss.aliyuncs/courses/640/live_http_headers.xpi
1.4 实验准备
1) 安装抓包插件Live Http Headers
打开 Linux Xfce 终端并通过wget命令下载插件⽂件。下载成功后⾸选右键单击xpi⽂件-->使⽤FireFox打开,之后按照界⾯提⽰安装Live Http Header 插件:
按照提⽰重启之后,通过打开菜单-->附加组件-->扩展到安装好的插件,点击⾸选项,勾选 Config 选项卡中的Open LiveHTTPHeaders in a new tab选项以⽅便使⽤。
2)启动web应⽤
由于实验楼会员环境中启动的 WebIDE 会占⽤ 8000 端⼝,所以如果是实验楼会员,请先停⽌ codebox 进程后再部署下⾯的 Web 应⽤。
使⽤ps -aux | grep codebox查询获得 codebox 的进程号,然后使⽤kill -9 进程号停⽌ codebox 进程。执⾏过程见下图:
⾸先安装demo依赖的web框架django,并测试是否安装成功:
$ sudo pip install django
$ python
>>> import django
>>> django.VERSION
django登录注册功能(1, 10, 0, u'final', 1)
再通过unzip命令解压⽹站⽂件,并启动⽹站服务。
$ wget labfile.oss.aliyuncs/courses/640/mysite.zip
$ unzip mysite.zip
$ cd mysite
$ ./manage.py runserver
⼆、分析登录过程
要通过编程实现登录,⾸先需要理解⼀般Web应⽤的登陆过程。
不同的⽹站和应⽤登录的安全性和复杂性都不同,因此它们的登录实现过程⾃然会存在差异,尽管如此,最基础,核⼼的过程依然是相同的。对于复杂的登录过程(例如淘宝),对请求包和响应包的分析能⼒是很重要的。
浏览器有⾃带的分析⼯具,但是界⾯⽐较窄,考虑到实验环境界⾯较⼩,本课程选择了 Live Http Header,同学们可以在本地选⽤任何⾃⼰喜欢的⼯具进⾏分析。我们先通过⽰例页⾯分析⼀下简单的登陆过程熟悉下分析过程。
2.1 抓取请求
1. 输⼊localhost:8000/polls打开登录页。
2. 打开live http header(F10->⼯具->Live Http Header)。
3. 输⼊⽤户名和密码(都是shiyanlou)并提交表单,登⼊系统。
4. 切换到Live Http Header页⾯查看http请求和响应信息
2.2原理分析
Live http Headers插件的Headers选项卡中会列出抓取到的所有的http请求和响应头,⼀次请求的url、请求和响应之间通过空⾏隔开,不同的请求之间通过虚线隔开。在按照2.1中的步骤登⼊系统后,我们在列表中看到了2个请求。第⼀个请求核⼼内容如下(还记得HTTP协议的内容吗?):
POST /polls/login HTTP/1.1 //请求⾏
******************** //此处省略其他请求头
Content-Type: application/x-www-form-urlencoded //请求实体类型
Content-Length: 41 //实体信息长度
name=shiyanlou&pwd=shiyanlou&commit=Login //实体内容
HTTP/1.0 302 Found //响应⾏,302重定向
Location: . //重定向的路径
******************** //此处省略其他响应头
Set-Cookie: sessionid=aped4pzerxjgd3db0ixw0dowkgrdpsxb;expires=Thu, 15-Sep-2016 15:04:28 GMT; httponly; Max-Age=1209600; Path=/ //响应头,服务器回写cookie
为什么是2个请求⽽不是1个呢?通过分析登录请求发现,登陆成功之后服务器发送了302重定向响应,服务器要求浏览器重新请求⾸页,这就产⽣了第⼆个请求。再来分析第⼆个请求,可以看到它相⽐登录请求多了⼀个请求头:
Cookie: sessionid=aped4pzerxjgd3db0ixw0dowkgrdpsxb
这个Cookie中的sessionid是从上⼀个响应头中的Set-Cookie⾏中获取,所以值相同。session的意思是会话,服务器通过session存储和维护与单个⽤户之间的会话信息。不同的⽤户在服务器端有不同的session,并且为了确保正常通信,每个⽤户的session都是唯⼀的。登录过程其实就是在验证⽤户登录信息后在session中存储⽤户登录标识的过程。在开发web应⽤时,“登陆成功”与“在session中存储⽤户登录标识”是等价的。整个登录流程如下图所⽰:
那么问题来了,服务器到底是如何区别不同⽤户的session的?为什么登陆成功会后要回写cookie呢?答案就是sessionid!每个⽤户的session都有独⽴的、唯⼀的编号sessionid⽤来标识⽤户⾝份。⽤户登录后,服务器通过从⽤户的session中读取登录标识来进⾏⾝份认证,因此必须要知道sessionid来访问⽤户的session,⽽使⽤cookie正是满⾜这个需求的⽅法。服务器将需要浏览器存储的信息通过Set-Cookie响应头发送给浏览器,浏览器会将cookie存储在本地,并在每次访问该⽹站时附带发送指定的cookie以满⾜服务器的需求,⽽通过cookie存储sessionid就是其中的⼀种应⽤。2.3⼩结
对于服务器来说,登录=验证+写session。对于浏览器来说,登录=发送登录信息+获取带sessionid的cookie。可以说,只要获得了sessionid,就算实现了模拟登录。有了它我们便可以游离于系统之中。
三、使⽤Python实现登录(简单实例)
理解了登录过程的原理和细节之后,开始⽤Python来编写模拟登陆程序吧。在任意⽬录下新建login_base.py⽂件,使⽤你喜欢的编辑器打开。实现流程如下:
3.1导⼊模块
不要忘记编写⽂件头、导⼊必要的依赖模块哦
#!/usr/bin/python
#-*- coding:utf-8 -*-
import urllib
import urllib2
import cookielib
3.2构造登录请求
⼀个http请求由3部分组成:请求url、请求头以及请求实体(附带数据)。在Python的urllib2库中,由urllib2.Request对象描述⼀个request。其中url是⼀个字符串、请求头是⼀个dict,key是请求头名称,value是请求头的内容。⾄于请求数据就要分具体情况了,在表单提交这种场景下,请求数据类型为application/x-www-form-urlencoded,意思就是经过url编码的表单数据,数据的组织形式是key=value,多组键值对之间⽤&分隔。登录请求的实体部分如下:
Content-Type: application/x-www-form-urlencoded //请求实体类型
Content-Length: 41 //实体信息长度
name=shiyanlou&pwd=shiyanlou&commit=Login //实体内容
此时,我们只需要使⽤dict来存储键值对,再⽤urllib.urlencode()⽅法进⾏编码就可以了。最后创建urllib2.Request对象,全部代码如下:
url = 'localhost:8000/polls/login'
values = {
'name':'shiyanlou',
'pwd':'shiyanlou',
'commit':'Login'
}
headers = {'Referer':'localhost:8000/polls/show_login'}
request = urllib2.Request(url,data=urllib.urlencode(values),headers=headers)
附加参数
需要注意的是,在浏览器页⾯操作时,⽤户只需要输⼊⽤户名和密码,看起来好像只需要提交2个参数到服务器。但实际上前端页⾯⼀般都会提交其他元参数到服务器,⼤多数都是与服务端的访问api设计有关,还有⼀些控制参数。⼀个登录请求包含5个以上的参数是再正常不过的事情,但并不是每⼀个参数都是登录所必要的,有些参数即使没有也不会影响正常登录。在实验demo中,commit这个参数就是必须提交的,否则会登录失败。
防盗链
Web 应⽤的资源都是有url的,只要获得了url就能够在任何地⽅引⽤。听起来很⽅便,但这可能会导致你的资源被别⼈盗⽤。为了访问量,把⾃⼰⾟⾟苦苦PS的⼀张美照放到个⼈站点上,却被别⼈的站点给引⽤⾛了,岂不是很⽓⼈?⽽HTTP的请求头Referer就是为了解决这类问题⽽⽣,Referer描述了当前请求的发出者,也就是引⽤者,服务器可以通过Referer来判断当前的引⽤者是否是合法的引⽤者从⽽决定是否返回请求的资源。考虑到⼀定的安全性,⼀般的⽹站登录都会限制Referer域来防⽌⾮法登录。因此,为了成功登录,我们需要在request头中填写Referer头,内容从抓取的请求头中照搬来即可。
3.3发送请求并保存cookie
⼀般情况下,打开url默认使⽤urllib2的urlopen()函数,但是它不能处理cookie。这⾥我们需要⾃⼰创建
能够存储cookie的opener。python内置有cookielib库来处理cookie,其中的MozillaCookieJar可以将cookie存储到⽂件中,并可以从⽂件中读取cookie。先创建MozillaCookieJar对象,再使⽤urllib2.HTTPCookieProcessor创建cookie处理器,最后使⽤urllib2.build_opener创建opener。接下来就可以⽤opener发送请求并存储cookie了。代码如下:# 创建opener
cookies = cookielib.MozillaCookieJar('') # 指定cookie的存储⽂件
cookie_handler = urllib2.HTTPCookieProcessor(cookies)
opener = urllib2.build_opener(cookie_handler)
# 发送请求 & 保存cookie
response = opener.open(request)
cookies.save()
de
ad()
如果登陆成功,就可以在指定的⽂件中看到sessionid了。
localhost.local FALSE / FALSE 1474019663 sessionid vejomjbliggkwblzfagobv3u8foik6am
3.4 使⽤cookie访问系统服务
在我们模拟登录成功后,就可以直接通过opener打开这个url来使⽤这项系统服务。代码实现如下:
url2 = 'localhost:8000/polls/date'
response2 = opener.open(url2)
de
ad()
如果有是在另外⼀个py⽂件中使⽤这个cookie的话,再打开url之前需要先载⼊cookie:
# 载⼊cookie
cookie = cookielib.MozillaCookieJar()
cookie.load('')
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
当然,以上只是⼀个简单的⽰例,只是为了说明原理。实际应⽤中的请求中会有各种各样的请求参数、元数据参数甚⾄是多样的验证cookie,只有理解了原理才能够以不变应万变。
四、⾼级登陆练习
是不是原理听懂了,但是只实现demo感觉不够过瘾?我们来⼀起做⼀做下⾯这个稍微难⼀点的练习吧。
4.1题⽬
已知信息:
登录页⾯url :
登录提交url :
⽤户名:admin
密码 : djangoadmin
要求:
模拟登陆成功并存储cookie
4.2 过程分析提⽰
管理员的登录请求的请求如下:
POST /admin/login/?next=/admin/ HTTP/1.1
Referer: localhost:8000/admin/login/?next=/admin/
Cookie: csrftoken=adxAiQKnRYgQoS4RmoooCesA7mBgJtwVnsd98nttE1arcBAnGwRbILLvWeS5xLfM
Content-Type: application/x-www-form-urlencoded
Content-Length: 137
csrfmiddlewaretoken=tsxs3KcOUt4ZdMg1gMBCKkNV8JTxZigaGHd1ThVUHwYA1vMxAU4pQR6QXBamNAZ1&username=admin&password=djangoadmin&next=%2Fadmin%2F HTTP/1.0 302 Found
Vary: Cookie
Last-Modified: Fri, 02 Sep 2016 09:24:46 GMT
Location: /admin/
Content-Type: text/html; charset=utf-8
Set-Cookie: csrftoken=seowCkz5vprAPZbkqF7M4QuzYZPKgoUrsO5nE3WWxtYnc5NRKB34rmmrTAIDdCaK; expires=Fri, 01-Sep-2017 09:24:46 GMT; Max-Age=31449600; Path=/ Set-Cookie: sessionid=cb6z7xlu31uxt8kdupfh0td43ewhgvpx; expires=Fri, 16-Sep-2016 09:24:46 GMT; httponly; Max-Age=1209600; Path=/
不难观察到登录请求中附带了csrftoken这个cookie,表单数据中必须提交csrfmiddlewaretoken,userna
me,password这三个参数,最后的next参数是url中附带的,不需要额外添加。必须得到前两个参数才能够成功登陆,这两个参数从名字上来看都⽤来作认证令牌,应该是由服务器⽣成的。其中的cookie肯定是来⾃上⼀个response的回写,⽽从csrfmiddlewaretoken的位置来看,应该是在登陆表单当中。注销登陆,重新进⼊登录页⾯,点击右键查看源代码发现了这个输⼊域(每次请求的值都是不同的):
<input type='hidden' name='csrfmiddlewaretoken' value='PSM5KbmRGdHraaVXK9UEzsWmLYlHxYjUPstWMUJIIheexgxu45QWWYOeGzeAuczd' />
这样⼀来我们的思路就很清晰了:
解析页⾯可以使⽤python的正则表达式re模块或者是⽐较⽕的beautifulsoup库。希望同学们先⾃⼰动⼿挑战⼀下,欢迎再课程回复中和我讨论,届时我将提供登录代码。
五、总结&扩展
模拟登陆的关键是弄清楚登录请求需要提交的参数,重点是要获取带有sessionid的cookie,最终⽬的是不受限制的访问系统提供的有价值的服务。
只有分析清楚登陆过程才能达到最终⽬的,这就需要具备强的HTTP包分析能⼒,理解HTTP协议,并配合包分析⼯具(FireBug,Live Http Header,Burp Suite等)解析出关键参数,有时需要编辑和重发包来删减掉不必要的多余参数。下⾯给出⼀些提⾼的参考资料,学有余⼒的同学可以深⼊研究:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论