Python实现网站模拟登录

1、实验简介

1.1 基本介绍

本实验中咱们将经过分析登录流程并使用 Python 实现模拟登录到一个实验提供的网站,在实验过程当中将学习并实践 Python 的网络编程,Python 实现模拟登录的方法,使用 Firefox 抓包分析插件分析网络数据包等知识。html

模拟登陆能够帮助用户自动化完成不少操做,在不一样场合下有不一样的用处,不管是自动化一些平常的繁琐操做仍是用于爬虫都是一项很实用的技能。本课程经过 Firefox 和 Python 来实现,环境要求以下:前端

  • Python 库:urllib, urllib2, cookielib, Django
  • Firefox 要求:装有 live http header插件 (已提供)

1.2 知识点

本项目中咱们将学习并实践如下知识点:python

  1. 网站登陆流程分析
  2. Python 网络编程基础
  3. Firefox 抓包分析插件 Live http header
  4. Python 模拟登录实现流程

1.3 实验材料

为了节省时间,实验用到的材料已经提早制做完成,能够按照材料清单中给出的连接下载。web

实验网站源码:
http://labfile.oss.aliyuncs.com/courses/640/mysite.zip FireFox抓包插件: http://labfile.oss.aliyuncs.com/courses/640/live_http_headers.xpi 

1.4 实验准备

1) 安装抓包插件Live Http Headers

打开 Linux Xfce 终端并经过 wget 命令下载插件文件。下载成功后首选右键单击xpi文件-->使用FireFox打开,以后按照界面提示安装Live Http Header插件:正则表达式

安装Live Http Header插件

点击安装

按照提示重启以后,经过 打开菜单-->附加组件-->扩展 找到安装好的插件,点击 首选项,勾选 Config 选项卡中的Open LiveHTTPHeaders in a new tab 选项以方便使用。django

插件设置

2)启动web应用

因为实验楼会员环境中启动的 WebIDE 会占用 8000 端口,因此若是是实验楼会员,请先中止 codebox 进程后再部署下面的 Web 应用。编程

使用 ps -aux | grep codebox 查询得到 codebox 的进程号,而后使用 kill -9 进程号 中止 codebox 进程。执行过程见下图:api

此处输入图片的描述

首先安装demo依赖的web框架django,并测试是否安装成功:浏览器

$ sudo pip install django
$ python
>>> import django >>> django.VERSION (1, 10, 0, u'final', 1) 

再经过unzip命令解压网站文件,并启动网站服务。安全

$ wget http://labfile.oss.aliyuncs.com/courses/640/mysite.zip $ unzip mysite.zip $ cd mysite $ ./manage.py runserver 

启动成功后在浏览器中输入 http://localhost:8000/polls 看到登陆页面表示启动成功。

解压并启动web应用

2、分析登陆过程

要经过编程实现登陆,首先须要理解通常Web应用的登录过程。

不一样的网站和应用登陆的安全性和复杂性都不一样,所以它们的登陆实现过程天然会存在差别,尽管如此,最基础,核心的过程依然是相同的。对于复杂的登陆过程(例如淘宝),对请求包和响应包的分析能力是很重要的。

浏览器有自带的分析工具,可是界面比较窄,考虑到实验环境界面较小,本课程选择了 Live Http Header,同窗们能够在本地选用任何本身喜欢的工具进行分析。咱们先经过示例页面分析一下简单的登录过程熟悉下分析过程。

2.1 抓取请求

  1. 输入http://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,就算实现了模拟登陆。有了它咱们即可以游离于系统之中。

3、使用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 = 'http://localhost:8000/polls/login' values = { 'name':'shiyanlou', 'pwd':'shiyanlou', 'commit':'Login' } headers = {'Referer':'http://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头,内容从抓取的请求头中照搬来便可。

通常状况下,打开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('my_cookies.txt') # 指定cookie的存储文件 cookie_handler = urllib2.HTTPCookieProcessor(cookies) opener = urllib2.build_opener(cookie_handler) # 发送请求 & 保存cookie response = opener.open(request) cookies.save() print response.code print response.read() 

若是登录成功,就能够在指定的文件my_cookies.txt中看到sessionid了。

localhost.local    FALSE / FALSE 1474019663 sessionid vejomjbliggkwblzfagobv3u8foik6am 

登陆系统只不过是一个开始,使用sessionid访问系统服务才是最终目的。举一个简单的例子,咱们的网站demo的首页中由一个查询系统当前时间的接口(在现实生活中多是更有用的,好比信息查询),咱们在登陆后点击它,能够看到它的url是http://localhost:8000/polls/date,这是只为登陆用户提供的服务。若是咱们如今返回首页,退出登陆以后直接在地址栏中输入这个url,页面将会302重定向至登陆页,没法看到当前时间。

首页图片

查看当前时间

在咱们模拟登陆成功后,就能够直接经过opener打开这个url来使用这项系统服务。代码实现以下:

url2 = 'http://localhost:8000/polls/date' response2 = opener.open(url2) print response2.code print response2.read() 

若是有是在另一个py文件中使用这个cookie的话,再打开url以前须要先载入cookie:

# 载入cookie cookie = cookielib.MozillaCookieJar() cookie.load('my_cookies.txt') opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) 

固然,以上只是一个简单的示例,只是为了说明原理。实际应用中的请求中会有各类各样的请求参数、元数据参数甚至是多样的验证cookie,只有理解了原理才可以以不变应万变。

4、高级登录练习

是否是原理听懂了,可是只实现demo感受不够过瘾?咱们来一块儿作一作下面这个稍微难一点的练习吧。

4.1题目

已知信息:

要求:

  • 模拟登录成功并存储cookie

4.2 过程分析提示

管理员的登陆请求的请求以下:

POST /admin/login/?next=/admin/ HTTP/1.1 Referer: http://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,username,password这三个参数,最后的next参数是url中附带的,不须要额外添加。必须获得前两个参数才可以成功登录,这两个参数从名字上来看都用来做认证令牌,应该是由服务器生成的。其中的cookie确定是来自上一个response的回写,而从csrfmiddlewaretoken的位置来看,应该是在登录表单当中。注销登录,从新进入登陆页面,点击右键查看源代码发现了这个输入域(每次请求的值都是不一样的):

<input type='hidden' name='csrfmiddlewaretoken' value='PSM5KbmRGdHraaVXK9UEzsWmLYlHxYjUPstWMUJIIheexgxu45QWWYOeGzeAuczd' /> 

这样一来咱们的思路就很清晰了:

登陆做业实现流程

解析页面可使用python的正则表达式re模块或者是比较火的beautifulsoup库。但愿同窗们先本身动手挑战一下,欢迎再课程回复中和我讨论,届时我将提供登陆代码。

5、总结&扩展

模拟登录的关键是弄清楚登陆请求须要提交的参数,重点是要获取带有sessionid的cookie,最终目的是不受限制的访问系统提供的有价值的服务。

只有分析清楚登录过程才能达到最终目的,这就须要具有强的HTTP包分析能力,理解HTTP协议,并配合包分析工具(FireBug,Live Http Header,Burp Suite等)解析出关键参数,有时须要编辑和重发包来删减掉没必要要的多余参数。下面给出一些提升的参考资料,学有余力的同窗能够深刻研究:

相关文章
相关标签/搜索