伪造一个系统的板Python学习教程-伪造Cookie会话管理

想学Python。关注小编头条号,私信【学习资料】即可免费领取全套系统板Python学习教程!

尝试登录

首先我们打开学校的教务系统,随便输入,然后提交表单,在Chrome的开发者工具中打开Network,准备抓包

过滤掉css图片之类的,找到了default.aspx之类的东西

如果您学校的教育系统不使用 cookie,就会出现这种情况

我们可以发现真正的请求地址是(bdq1aj45lpd42o55vqpfgpie)/default2.aspx

然后我们发现这个URL括号里的那一串信息有点奇怪,而且每次输入的信息都不一样。数据查询后,这是 ASP.NET 不使用 Cookie 会话管理的技术。

没有 cookie 的 ASP.NET 会话管理

那么这就好办了,我们只需要在登录的时候记录这些数据就可以保持登录状态。

经过测试发现我们可以只伪造一个会话信息来一直保持登录状态,但是为了体现模拟登录的科学性,我们需要先获取会话信息。

如果您学校的教育系统使用 cookie,就会发生这种情况

服务端会返回一个cookie值,然后保存在本地asp没有验证码定义,和下面的会不一样。

获取会话信息(无 cookie)

这里我们要使用requests库,伪造header的UA信息

经过测试asp没有验证码定义,我们发现我们只访问学校的IP地址,它会自动重定向到带有会话信息的URL,所以我们先访问IP地址。

class Spider:
 def __init__(self, url):
 self.__uid = ''
 self.__real_base_url = ''
 self.__base_url = url
 self.__headers = {
 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36',
 }
 def __set_real_url(self):
 request = requests.get(self.__base_url, headers=self.__headers)
 real_url = request.url
 self.__real_base_url = real_url[:len(real_url) - len('default2.aspx')]
 return request

上面得到的URL是带有会话信息的URL,保存的URL格式为(bdq1aj45lpd42o55vqpfgpie)/

以这种格式保存,因为我们要访问其他地址

获取会话信息(使用 cookie)

部分学校的教务系统使用cookies。我们只需要在第一次get请求时保存cookie,然后一直使用cookie。

def get_cookie():
 request = requests.get('http://xxx.xxx.xxx.xxx') #以某教务系统为例子
 cookie = requets.cookie
 return cookie

并且在请求中使用 cookie 非常简单

只需要这个

def use_cookie(cookie):
 request = requests.get('http://xxx.xxx.xxx.xxx',cookie=cookie)

由于我们学校采用的是无cookie的方案,所以下面的代码不发送cookie。如果你的学校采用 cookie,你只需要像我上面做的那样发送 cookie。

而如果你的学校使用cookies,你就不必通过session信息获取地址,直接存储cookie即可。

或者可以使用请求的Session来自动管理会话信息,这样文章下面代码中的所有请求都可以改为Session请求,但是需要先在类的初始化方法中进行初始化。

def __init__(self):
 self.session = requests.Session()

然后我们首先访问该网站一次以获取cookie并存储它

def get(self):
 r = self.session.get(url,headers=headers)

更多用法可以查询文档

验证码的处理

分析r返回的文本信息

找到验证码标签的资源地址是src=”CheckCode.aspx”,我们可以直接请求然后下载验证码图片。下载图像的一种优雅方式如下

def __get_code(self):
 request = requests.get(self.__real_base_url + 'CheckCode.aspx', headers=self.__headers)
 with open('code.jpg', 'wb')as f:
 f.write(request.content)
 im = Image.open('code.jpg')
 im.show()
 print('Please input the code:')
 code = input()
 return code

以上代码将图片保存为code.jpg,Python有一个Image模块可以自动打开图片

图片[1]-伪造一个系统的板Python学习教程-伪造Cookie会话管理-老王博客

这样验证码就显示出来了,我们可以手动输入,也可以传到编码平台。

登录数据的构建

这是上面抓到的登录帖子的数据包,

发现有信息无法解码,应该是gb2312编码,解码前检查编码

然后把不能解码的代码复制到能解码的地方

发现%D1%A7%C9%FA编解码是学生

这也对应于学生选项的登录。

学号、密码和验证码可以清楚的知道是什么信息,但是我们发现有一个__VIEWSTATE项

查一下,这是一种隐藏形式的信息,我们可以使用 BeautifulSoup 库来解析这一项数据的值

这是完整的登录数据包,

def __get_login_data(self, uid, password):
 self.__uid = uid
 request = self.__set_real_url()
 soup = BeautifulSoup(request.text, 'lxml')
 form_tag = soup.find('input')
 __VIEWSTATE = form_tag['value']
 code = self.__get_code()
 data = {
 '__VIEWSTATE': __VIEWSTATE,
 'txtUserName': self.__uid,
 'TextBox2': password,
 'txtSecretCode': code,
 'RadioButtonList1': '学生'.encode('gb2312'),
 'Button1': '',
 'lbLanguage': '',
 'hidPdrs': '',
 'hidsc': '',
 }
 return data

登录

如果登录完成,如何判断是否登录成功?我们从登录成功返回的界面中发现有一个name的标签,而我们等待的时候也需要学生的名字,所以我们以此为依据来判断登录是否成功。

代码如下,区分验证码用户名和密码的提示信息

def login(self,uid,password):
 while True:
 data = self.__get_login_data(uid, password)
 request = requests.post(self.__real_base_url + 'default2.aspx', headers=self.__headers, data=data)
 soup = BeautifulSoup(request.text, 'lxml')
 try:
 name_tag = soup.find(id='xhxm')
 self.__name = name_tag.string[:len(name_tag.string) - 2]
 print('欢迎'+self.__name)
 except:
 print('Unknown Error,try to login again.')
 time.sleep(0.5)
 continue
 finally:
 return True

获取选课信息

下一步是获取课程选择信息。这里我们以学校公开课选课为例,点开,抓包。标题中没有什么需要注意的。我们只需要关注get发送的包裹即可。

发现有一个学号、姓名和gnmkdm。名称需要以gb2312的形式编码传输

这里我们注意到headers需要添加一个Referer项,也就是当前访问的URL,才能发出请求

def __enter_lessons_first(self):
 data = {
 'xh': self.__uid,
 'xm': self.__name.encode('gb2312'),
 'gnmkdm': 'N121103',
 }
 self.__headers['Referer'] = self.__real_base_url + 'xs_main.aspx?xh=' + self.__uid
 request = requests.get(self.__real_base_url + 'xf_xsqxxxk.aspx', params=data, headers=self.__headers)
 self.__headers['Referer'] = request.url
 soup = BeautifulSoup(request.text, 'lxml')
 self.__set__VIEWSTATE(soup)

注意上面有个设置VIEWSTATE值的函数,后面在选择课程和构建数据包的时候会讲到。

模拟课程选择

随便挑一门课程,然后提交,抓包,看看发了什么数据

前三个值可以在原始网页的输入标签中找到。由于前两项为空,所以不会获取,第三项可以通过汤分析获取。由于这个操作每次被请求都会改变,我们把它写成一个每次请求完成时设置的函数。

 def __set__VIEWSTATE(self, soup):
 __VIEWSTATE_tag = soup.find('input', attrs={'name': '__VIEWSTATE'})
 self.__base_data['__VIEWSTATE'] = __VIEWSTATE_tag['value']

对于其他数据,我们可以通过搜索响应网页了解它们的用途。这里我只描述我们使用的数据。

TextBox1是搜索框数据,我们可以用这个来搜索课程,dpkcmcGrid:txtPageSize是一页显示多少数据,经过测试,服务器最多响应200条。

值得注意的是ddl_xqbs的校园数据信息,我的校园编号为2,可能不同学校设置不同,需要自己设置,也可以从网页获取

以下是基本数据包。由于我们需要使用这个基础数据包来搜索课程和选择课程,所以我们直接在init函数中添加。

 self.__base_data = {
 '__EVENTTARGET': '',
 '__EVENTARGUMENT': '',
 '__VIEWSTATE': '',
 'ddl_kcxz': '',
 'ddl_ywyl': '',
 'ddl_kcgs': '',
 'ddl_xqbs': '2',
 'ddl_sksj': '',
 'TextBox1': '',
 'dpkcmcGrid:txtChoosePage': '1',
 'dpkcmcGrid:txtPageSize': '200',
 }

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论