基于node连接广工大服务器获取信息

观察登录形式

提交一次登录观察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.str
  postVerity(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 = verifycode
    let 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就能操作任何事情)

猜你喜欢

转载自blog.csdn.net/ccy_888/article/details/125654526