观察登录形式

提交一次登录观察http报文,查看携带的参数,一般登录要么携带cookie,要么携带token。

如图所示,肯定是携带cookie作为验证身份的值,提交账号密码和验证码即可登录。可以确定,通信方式如下图所示。

获取cookie的方法

  1. document.cookie获取
  2. 拦截响应报文获取set-cookie字段

由于w3c规定浏览器不能拿到响应报文的set-cookie字段所以先打开浏览器的控制台,直接输入document.cookie,发现是空值。

打开应用程序的cookie那里又显示了cookie值,清空cookie然后重新刷新浏览器查看http报文发现

服务器在set-cookie字段设置了secure;httponly,所以无法通过document.cookie获取。显然,直接通过浏览器没办法登录了。
那么考虑第二种,w3c只是不允许浏览器拿到响应报文的set-cookie但是服务器可以。
所以采用的方法,通过服务器与工大服务器进行通信,客户端再与自建服务器进行通信,所有操作通过自建服务器进行操作。解决了跨域和cookie的问题。
通过上述的http报文得知了登录的形式。
直观上来说就是通过网页可以看到提交的表单就是账号、密码和验证码。但是显然这些不会直接就发送,会进行一定的加密,加密方法可以通过源码进行观察。

开始搭建服务器

大致的方法

通过源码观察如何获取验证码,可以看到直接通过Date().getTime()作为参数去请求地址。

采用node.js搭建服务器。因为浏览器是要连接自建的服务器,所以要处理接收的http请求,自建服务器又需要请求工大服务器,也就是需要发送http请求。
第三方库介绍

  1. axios 发送请求
  2. express 接收请求
  3. body-parser 处理接收请求格式
  4. btoa 处理发送请求图片问题
  5. cors 解决跨域问题
  6. crypto-js 解决加密问题
  7. qs 解决发送请求post问题

最终验证

通过node server.js开启服务

const express = require("express"),
cors = require('cors'),
bodyParser = require("body-parser"),axios = require('axios'),
CryptoJS = require('crypto-js'),
btoa = require('btoa'),
qs = require('qs');
// 使用框架创建web服务器
const app = express();
//解决跨域问题
app.use(cors());
// 解决请求参数格式问题
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }))var cookie = ''// 当客户端以get方式访问/路由时
app.get('/xs_http/getVerity', (req, res) => {  let currentTime = new Date().getTime();axios.get(`https://jxfw.gdut.edu.cn/yzm?d=${currentTime}`,{responseType: 'arraybuffer'},{headers: {"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"keep-alive","Cache-Control": "no-cache"}}).then(response=>{try{cookie = response.headers['set-cookie'][0].split(';')[0];} catch{};let data = btoa(new Uint8Array(response.data).reduce((data, byte) => data + String.fromCharCode(byte), ''));res.json({base64: data});})
});// 当客户端以post方式访问/路由时
app.post('/xs_http/post',(req,res)=>{let str = req.body.strpostVerity(str).then((cookie)=>{// console.log(cookie);res.send(cookie);})
});// 当客户端以get方式访问/路由时
app.get('/xs_http/gdut_grade', (req, res) => {  let data = {rows: 60,sort: 'xnxqdm',order: 'asc',page: '1',jhlxdm: ''}axios.post(`https://jxfw.gdut.edu.cn/xskccjxx!getDataList.action`,qs.stringify(data),{headers: {"Accept":"application/json, text/javascript, */*; q=0.01","Accept-Encoding":"gzip, deflate","Connection":"keep-alive","Cookie": cookie,"Cache-Control": "no-cache","Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}}).then(response=>{try{cookie = response.headers['set-cookie'][0].split(';')[0];} catch{};res.send(response.data)})
});//启动端口监听
var server = app.listen(20000, function () {console.log('服务端已开启')
});function postVerity(verifycode){return new Promise((resolve,reject)=>{const keycode = verifycodelet key = CryptoJS.enc.Utf8.parse(keycode+keycode+keycode+keycode);var srcs = CryptoJS.enc.Utf8.parse('你的密码');let encryptedData  = CryptoJS.AES.encrypt(srcs, key, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});let hexData = encryptedData.ciphertext.toString();let data = {account: '你的账号',pwd: hexData,verifycode: keycode}console.log(data,'\n',cookie);axios.post(`https://jxfw.gdut.edu.cn/new/login`,qs.stringify(data),{headers: {"Accept":"application/json, text/javascript, */*; q=0.01","Accept-Encoding":"gzip, deflate","Connection":"keep-alive","Cookie": cookie,"Cache-Control": "no-cache","Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}}).then(res=>{try{cookie = res.headers['set-cookie'][0].split(';')[0];console.log('请求cookie变了')} catch{};console.log(res.data);resolve(cookie)})})
}

写html模拟客户端

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<style>
.button{display: inline-block;width: 100px;height: 25px;line-height: 25px;text-align: center;background-color: #ddd;cursor: pointer;
}
</style>
<body><div><div id="request1" class="button">请求</div></div><input id="text" type="text"><div id="request2" class="button">发送</div><img id="img" src=""><div id="request3" class="button" >获得成绩</div>
</body>
</html>
<script>
document.getElementById('request1').onclick = function(){getQR().then((res)=>{// document.getElementById('request3').click();let obj = JSON.parse(res)document.getElementById('img').src = 'data:image/png;base64,' + obj['base64'];// let data = JSON.parse(res);// document.getElementById('img').src = data.url;})
}
document.getElementById('request2').onclick = function(){let text = document.getElementById('text').value;postQR(text).then(res=>{// let obj = JSON.parse(res)console.log(res)// document.getElementById('img').src = 'data:image/png;base64,' + obj['base64'];})
}
document.getElementById('request3').onclick = function(){let xhr=new XMLHttpRequest() xhr.onreadystatechange=function () {if (xhr.readyState == 4) {console.log(xhr.response);}}xhr.open('get','http://localhost:20000/xs_http/gdut_grade' ) // 发送数据到后端xhr.send()
}
function getQR(){return new Promise((resolve,reject)=>{let xhr=new XMLHttpRequest() // 在xhr的准备状态发生改变的时候,调用该方法xhr.onreadystatechange=function () {// 判断xhr的准备状态if (xhr.readyState == 4) {resolve(xhr.response)}}xhr.timeout = 10000;xhr.ontimeout = function() {alert("网络延迟,请稍后再试");}xhr.addEventListener('load',function(){if(xhr.status>=200&&xhr.status<300||xhr.status===304){var data=xhr.responseText;// console.log(data)}else{console.log('error')}});// open方法里面要放置两个参数,// 参数1:数据请求方式 get post// 参数2:请求的接口,参数在接口后面进行拼接xhr.open('get','http://localhost:20000/xs_http/getVerity' ) // 发送数据到后端xhr.send()})
}
function postQR(str){return new Promise((resolve,reject)=>{let xhr=new XMLHttpRequest() // 在xhr的准备状态发生改变的时候,调用该方法xhr.onreadystatechange=function () {// 判断xhr的准备状态if (xhr.readyState == 4) {resolve(xhr.response)}}// open方法里面要放置两个参数,// 参数1:数据请求方式 get post// 参数2:请求的接口,参数在接口后面进行拼接xhr.open('post','http://localhost:20000/xs_http/post') // 发送数据到后端xhr.setRequestHeader ('Content-type', 'application/x-www-form-urlencoded');xhr.send(`str=${str}`)})
}
</script>

完整版文件压缩包

链接:https://pan.baidu.com/s/1zRUKg9cuMkSQP9ZL5alPaw
提取码:0000

期间遇到的问题

对浏览器原生xhr请求不熟悉
对axios不熟悉,post请求需要配合qs库
对图片get请求不熟悉,需要配置参数通过buffer来获取res.data
尝试自动识别,考虑了Tesseract.js发现误差太大,弄了好久,放弃了

拓展

这个简单实现了请求成绩的demo
通过抓包,可以分析请求课表等教务系统的所有信息,甚至可以抢课(只需要登录后的cookie就能操作任何事情)

基于node连接广工大服务器获取信息相关推荐

  1. Node.js毕业设计——基于Node.js+JavaScript+MongoDB的供求信息网站设计与实现(毕业论文+程序源码)——供求信息网站

    基于Node.js+JavaScript+MongoDB的供求信息网站设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于Node.js+JavaScript+MongoDB的供求信息网站设计 ...

  2. 无法从服务器中获取信息吗,无法从服务器获取信息

    无法从服务器获取信息 内容精选 换一换 查询配额信息.GET /v2/{project_id}/os-quota-sets/{project_id}参数说明参数是否必选参数类型描述project_id ...

  3. Android 从服务器获取信息 并显示 (包含服务器端代码)

    服务器端代码 Bookjavabean和app端保持一致 将书籍信息的list转换成json 生成gson数据 app端请求的urlhttp1151591521798080Baidudemoservl ...

  4. 微信小程序基于node.js的websocket服务器搭建和SSL证书申请、配置全家桶

    〇.前言 最近在研究微信小程序的开发,中间遇到了不少问题,趟了不少坑,这里和大家分享一下我的一些经验,希望能给大家提供一些帮助. 一.微信小程序的websocket服务器搭建 微信小程序的网络通信使用 ...

  5. 鲁大师从服务器获取信息失败怎么办,云服务器 鲁大师

    云服务器 鲁大师 内容精选 换一换 系统盘:云服务器中安装操作系统的云硬盘,类似于电脑中的C盘.系统盘在购买云服务器时自动购买并挂载,无法单独购买.系统盘的最大容量为1024 GB.系统盘在购买云服务 ...

  6. adfs服务器获取信息失败,在ADFS服务器上SAML LogOutRequest处理失败

    我有ADFS服务器作为IdP.我有单独的SP应用程序.这些在信任圈定义.基于SAML协议的SSO工作正常.当我尝试使用SP启动的注销请求时,我在ADFS端发生错误:在ADFS服务器上SAML LogO ...

  7. adfs服务器获取信息失败,在使用Fiddler或其他诊断工具时无法登陆到ADFS服务器

    在使用Fiddler或其他诊断工具时无法登陆到ADFS服务器 03/29/2016 2 分钟可看完 本文内容 问题描述: 当使用Fiddler或其他诊断工具进行ADFS 排错时,用户从内部登录ADFS ...

  8. 打印机无法从服务器获取信息,win10系统安装打印机提示无法从Windows Update获取设备列表怎么办...

    最近有win10系统用户到本站咨询这样一个情况,就是要安装打印机的时候,突然提示无法从Windows Update获取设备列表怎,遇到这样的问题该怎么办呢,本文就给大家讲解一下win10系统安装打印机 ...

  9. DNF从服务器获取信息失败,dnf显示服务器读取中进不去怎么办 dnf显示服务器读取中进不去解决方法...

    dnf服务器读取中,进不去怎么办? dnf服务器读取中,进不去有这么几种可能:1.这个时段在线的人太多,等一段时间就好了. 2.去官方查看是否有消息说系统正在维护. 3.网速太慢. 4.系统有病毒 5 ...

  10. 荣耀10 无法从服务器获取信息,荣耀10最新资讯

    王者荣耀在10月29日开启了更新维护,其中对服务器进行了优化升级,很多玩家还不清楚到底更新了什么,下面就来为大家详细的介绍一下. 王者荣耀在10月27日这天开启了不停服的更新维护,此次的更新内容还是比 ...

最新文章

  1. 详细的多维度测评,看看哪个 Python 版本速度最快!
  2. task一个任务结束后执行另一个操作
  3. TCP/UDP,SOCKET,HTTP,FTP协议简析
  4. SAP UI5 初学者教程之十 - 什么是 SAP UI5 应用的描述符 Descriptor 试读版
  5. java exception 行号_java日志记录错误的文件_方法_行号_报错信息
  6. java rsa 117_java实现RSA非对称加密解密
  7. leetcode-92-反转链表②
  8. 面向对象设计原则之6-合成复用原则
  9. centos 7安装_OrthoMCL软件安装
  10. linux下scrapy安装教程,linux centos7安装scrapy
  11. 问答 | 为什么car-like robot转向机构需要使用等腰梯形?
  12. win10任务栏透明_手把手教你把win10桌面变得逼格满满(任务栏可以透明哦)
  13. win10计算机不显示usb,win10插入U盘不显示怎么办_解决win10u盘插电脑上不显示的办法...
  14. Python学习——三分钟分析目前最火的电视剧
  15. 终于可以不用radmin了
  16. Android开发人口流动管理,Android轻松搞定流动布局
  17. 【完成】桌面窗口层次(Z-Order 记录文档)
  18. stunnel安装及设置
  19. 地图服务器控件GIS Map Server v3.6发布,新增航空影像数据集功能
  20. js中如何判断字符串相等

热门文章

  1. 不到一周我开发出了属于自己的知识共享平台
  2. 计算机网卡接口类型,一文带你全方位了解网卡
  3. k8s部署rabbitMQ集群
  4. 12 如何分析kernel panic?
  5. 致远OA表单自定义函数(明细表去重拼接)
  6. 动态规划——01背包——精卫填海
  7. G - Numbers ZOJ - 3987 (大数+贪心)
  8. 2021年终总结:鲜花怒马少年时,一日看尽长安花
  9. [Joy]冷笑话急转弯
  10. 调用登录接口返回“参数错误”