浅笑博客
不要以为抹消过去,重新来过,即可发生什么改变。
浅笑博客
兰大智慧一卡通平台的模拟登录实现
兰大智慧一卡通平台的模拟登录实现

本文主要对兰大智慧一卡通平台的登录验证原理进行分析并介绍,并且使用python模拟实现登录。 虽然通过个人工作台的登录可以无需验证码直接跳转登录至智慧一卡通平台(尽管个人工作台的登录使用什么 recaptcha 的验证,也可以通过App端登录获取TGT、ST的接口绕过),但本文主要分享的是智慧一卡通平台验证原理和通过获取并使用接口识别验证码进行登录。

选择此平台做测试的主要原因还有一个就是它的验证码可识度较高,大家一样都能认,当然机器判断也简单许多,识别成功率也较高。

http://blog.qianxiao.fun/wp-content/uploads/2020/09/火狐截图_2020-09-29T07-34-06.969Z-1024x458.png

进入登录页面,由于有图片验证码,因此一般情况会存在通信的session。

查看获取验证码请求 https://ecard.lzu.edu.cn/jcaptcha.jpg :

http://blog.qianxiao.fun/wp-content/uploads/2020/09/图片-1024x661.png

发现请求cookie sid,因此这个sid应该就是通信验证验证码的凭据。看下它是从哪里来?

http://blog.qianxiao.fun/wp-content/uploads/2020/09/图片-1-1024x661.png

发现是加载登录页面时响应的cookie,因此该值容易获取,直接get登录页面获取响应cookie即可获取。

接下来就是登录请求模拟了,首先抓一次登录,如下:

http://blog.qianxiao.fun/wp-content/uploads/2020/09/图片-2-1024x661.png

登录时发现关键登录的请求为post请求 https://ecard.lzu.edu.cn/lzulogin ,不过发现登录请求是加密的。发现在做登录请求前有一post请求 https://ecard.lzu.edu.cn/publiccombo/keyPair,如下。根据返回信息判断应该rsa加密的参数。

http://blog.qianxiao.fun/wp-content/uploads/2020/09/图片-3-1024x661.png

exponent和 modulus 可以理解为就是rsa公钥,也就是登录请求前先请求获取rsa公钥,然后进行rsa加密。这里我们也可以查看网页登录的js逻辑来帮助我们分析,这里可以通过堆栈跟踪来看是哪的js发起的请求。

http://blog.qianxiao.fun/wp-content/uploads/2020/09/图片-5-1024x661.png
http://blog.qianxiao.fun/wp-content/uploads/2020/09/图片-6-1024x661.png

发现,通过keyPair请求获取 exponent和 modulus 后通过生成RSA公钥然后进行加密数据(这里由于它调用的是自己js内实现的RSA加密,所以它的加密有可能不同,这里我用python的rsa加密请求测试发现请求失败,也正说明这个问题)。然后做登录请求。大概逻辑有了,简单画了个大概的流程图如下:

http://blog.qianxiao.fun/wp-content/uploads/2020/09/未命名文件.png

接下来就是使用python模拟实现了,原理都有了,实现起来便是非常方便,需要注意的也是上面所说的,它根据 exponent和 modulus 不一定是标准生成rsa公钥,以及加密是否是标准加密,所以这里用到了PyExecJS模块,即python调用js。对于验证码的识别其实也可以使用训练模型来处理,这里我为了方便直接使用接口调用来识别了。具体Python实现代码如下:

# -*- coding:utf8 -*-
#python3.6.8
#QianXiao
#代码只供参考学习
import requests
import json
#pip3 install PyExecJS
import execjs
from PIL import Image
from sys import version_info
import base64
from io import BytesIO
import os
import sys
import time

'''
图鉴
验证码识别
'''
def base64_api(uname, pwd,  img):
    if version_info.major >= 3:
        b64 = str(base64.b64encode(img), encoding='utf-8')
    else:
        b64 = str(base64.b64encode(img))
    data = {"username": uname, "password": pwd, "image": b64}
    result = json.loads(requests.post("http://api.ttshitu.com/base64", json=data).text)
    #print(result)
    if result['success']:
        return result["data"]
    else:
        print(result["message"])
        return None
def reportError(id):
    data = {"id": id}
    result = json.loads(requests.post("http://api.ttshitu.com/reporterror.json", json=data).text)
    if result['success']:
        return "报错成功"
    else:
        return result["message"]
    return ""


#获取sid
#为了方便同步cookie这里使用session
session = requests.session()
headers = {
                "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
                "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
                "Connection": "Keep-Alive",
                "Referer":"https://ecard.lzu.edu.cn/lzulogin"
        }
r = session.post(url="https://ecard.lzu.edu.cn/lzulogin",headers=headers)

#获取并识别验证码
data = {}
yzflag = False
while yzflag == False:
  r = session.get(url="https://ecard.lzu.edu.cn/jcaptcha.jpg?t="+str(int(time.time()*1000)),headers=headers)
  img = r.content
  result = base64_api(uname='**********', pwd='***********', img=img)
  if result==None:
    exit()
  print("验证码识别结果:"+result['result'])
  id = result['id']
  data["jcaptchacode"] = result['result']
  headers = {
                  "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
                  "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
                  "Connection": "Keep-Alive",
                  "Referer":"https://ecard.lzu.edu.cn/lzulogin",
                  "X-Requested-With":"XMLHttpRequest"
          }
  r = session.post(url="https://ecard.lzu.edu.cn/publiccombo/keyPair",headers=headers)
  jsondata = json.loads(r.text)
  e = jsondata['publicKeyMap']['exponent']
  n = jsondata['publicKeyMap']['modulus']
  #python调用js
  with open('security.js') as f:
    jsdata = f.read()
  x = execjs.compile(jsdata)
  data["username"] = x.call('rsaJSencrypt', '320160939471', e,n)
  data["password"] = x.call('rsaJSencrypt', '******', e,n)
  r = session.post(url="https://ecard.lzu.edu.cn/lzulogin",headers=headers,data=data)
  jsondata = json.loads(r.text)
  if jsondata['ajaxState'] == "3":
    print("登录成功")
    yzflag = True
  elif jsondata['msg'] == "验证码错误":
    print("验证码错误")
    result = reportError(id=id)
    print("重新获取验证码")
  else:
    yzflag = True
    print(r.text)
    exit()

#登录成功后的cookie(sid)可直接显示页面
headers = {
                "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
                "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
                "Connection": "Keep-Alive",
                "Referer":"https://ecard.lzu.edu.cn/lzulogin",
        }
r = session.get(url="https://ecard.lzu.edu.cn/",headers=headers)
#print(r.text)
if "胡光邦" in r.text:
  print("success")

运行结果:

http://blog.qianxiao.fun/wp-content/uploads/2020/09/图片-7.png

以上便是对其模拟登录的实现,其中验证码识别我使用的是图鉴平台(http://sb.daredian.cn/),价格也比较实惠(0.2厘/次 ),我也是仅买了2块钱做测试学习用。上面的代码总体上就是根据上面所说的逻辑流程实现,代码写的简单,关键位置我已注释,如有疑问可评论交流或与我联系。

文章一开始才也说了,本文只做有验证码的识别模拟登录的学习和分享。由于个人工作台可直接使用cookie跳转至给该平台,且个人工作台的验证看通过App端抓的请求(TGT、ST)绕过,所以真正要是需要使用此平台的模拟登录我推荐还是使用TGT、ST绕过个人工作台验证,之后通过个人工作台的cookie即可直接跳转登录到该平台,实际测试中发现,跳转时关键cookie还是那个TGT,所以无需图片验证码直接使用TGT还是可以登录该平台的(主要不仅方便不用花钱验证码识别了)。

简单实现如下:

# -*- coding:utf8 -*-
#coding=utf-8
#python2.7
#QianXiao
#代码只供参考学习
import requests
import json
import sys
import re

headers = {
                "Content-Type": "application/x-www-form-urlencoded",
                "User-Agent": 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12',
                "Host": "appservice.lzu.edu.cn",
                "Connection": "Keep-Alive",
                "Accept-Encoding": "gzip",
        }  
data = 'username=****&password=***********'
r = requests.post(url="https://appservice.lzu.edu.cn/api/lzu-cas/v1/tickets",headers=headers,data=data)
jsondata = json.loads(r.text)
action = jsondata['action']
tgt = re.findall('.([^/]*)$', action)[0]
#print(tgt)
cookies = {"iPlanetDirectoryPro":tgt}
r = requests.get(url="https://ecard.lzu.edu.cn/lzulogin",cookies=cookies,allow_redirects=False)
cookies.update(requests.utils.dict_from_cookiejar(r.cookies))
print(cookies)

headers = {
                "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
                "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
                "Connection": "Keep-Alive",
                "Referer":"https://ecard.lzu.edu.cn/lzulogin",
        }
r = requests.get(url="https://ecard.lzu.edu.cn/",headers=headers,cookies=cookies)
#print(r.text)
if "胡光邦" in r.text:
  print("success")

关于本文,如有任何疑问或建议,欢迎评论交流或与我私信。如有任何错误或不足,请不吝指正。

没有标签
首页      未分类      兰大智慧一卡通平台的模拟登录实现

发表评论

textsms
account_circle
email

浅笑博客

兰大智慧一卡通平台的模拟登录实现
本文主要对兰大智慧一卡通平台的登录验证原理进行分析并介绍,并且使用python模拟实现登录。 虽然通过个人工作台的登录可以无需验证码直接跳转登录至智慧一卡通平台(尽管个人工作台的登…
扫描二维码继续阅读
2020-09-29