前言:最近看网上国网项目跑的很火,于是扒了一个查询新老号的接口,做一次node服务的项目部署,顺便也算是练一下手吧。 查询链接:网上国网查询新老号接口 PS:没注册过的算是新号,注册过的算是老号。
一、接口逆向扒取,分析入参与返回参数
1.走一遍完整流程,找到需要的数据
1.Chrome浏览器打开上述链接,并开启控制台,切换成手机模式,并清空**netWork**选项卡,输入手机号(本人输入的手机号都是随机生成的,并不涉及任何隐私信息),点击发送验证码
2.此时,会有两种情况弹窗出现,一种是“验证码发送成功”,另一种提示是“输入的手机号已注册”
3.这时候我们看network选项卡,会出现一条新的请求,如下:
此种情况,很明显代表,该手机号码已经注册,这时候我们来看具体的抓包数据
我们主要看payload也就是负载,因为是post请求,则一定会带请求数据的,只带了一个jsonString的参数,开头是eyj...我们基本可以肯定这就是个加密了,里边一定包含了我们的手机号信息。
具体的加密入参的整个逆向过程,就不在这里多讲述了 上图已经有部分总结。我们主要关注的是t数据的构造数据过程里面的每一个字段,是干什么用的,到底会对我们的最终结果产生什么影响?这个我们一定要搞明白,不然不知道哪些参数有用,哪些参数没用就坏事了。 k7: this.encrypt.encrypt(this.refs.name.value这个参数在经过我们断点之后,我们就可以知道,这是我们用户输入的手机号,经过this.encrypt.encrypt这个方法加密之后,就变成了一串看不懂的字符串。
经过我们的断点进入这个方法,我们能发现,他貌似用了JSEncrypt这个前端加密库,然后用了rsa加密。我们知道,rsa加密,必须要有一个公钥publicKey的,然后后端再用私钥解密数据,去数据库查询,才能确定我们的手机号到底注册过没有。思路明确之后,我们先找一下公钥
直接搜索,我们便找到了设置公钥的方法,同样也找到了公钥。然后看代码的话,最后还对我们的数据,做了一个base64的加密,这个我们也要去还原一下,不然数据是对不上的,加密就是这俩,大体的思路还有方式都说完了,现在就该考虑如何将代码实现在node后端了。
2.来看返回数据
返回数据很明显又是一个base加密的数据,也需要我们解密才能查看
二、win系统node代码编写
如果想要实现上面的两处加密和返回数据的解密,就需要在node端实现JSEncrypt加密以及base64加解密,其中base64加解密node后端自带,现在需要找一个代替前端加密库JSEncrypt的库,可以在node上运行 直接google解决,node-jsencrypt库可以进行替代
直接贴代码,复现上述加解密实现 index.js
const express = require('express')
const bodyParser = require('body-parser');
const url = require('url');
const JSEncrypt = require('node-jsencrypt');
const axios = require('axios');
const { Buffer } = require('buffer');
const encrypt = new JSEncrypt();
//首先定义公钥
const publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNN7crxSsgp5llYivZ7javkS/ff5ux4LgDc9HiU82l9EZ4/s3mLKIr3E2+iQb9URXmGw706Nmn6u1XWaNfctTAE8RdVJXKWjIINHW/oxjJksbGfCDq4yaZUQrpW1/T+uhHVRRA0pfjVY1w4le9c0rTCci800ovr0pNdJzNuN56DQIDAQAB';
encrypt.setPublicKey(publicKey);
//设置主机名
const hostName = '0.0.0.0';
//设置端口
const port = 9001;
const app = express();
const routes = express.Router();
//设置路由访问路径和静态资源目录
app.use("", routes);
const server = app.listen(port, hostName, (err) => {
if (err) {
console.log(err)
} else {
console.log(`服务开启成功【端口号:${port}】`)
}
});
/**
* express建立GET接口
* http://192.168.200.1:9000/a/ab?name='name12'&pwd='123'
*/
routes.get('/search', (req, res) => {
//解析参数
const params = url.parse(req.url, true).query;
console.log("前端入参:",params)
if (!params?.phone) {
const responseJson = {status: 201, msg: '请检查传参,传参只能是phone',data:{}};
res.send(responseJson)
}
encrypt_wsgw(params.phone).then(data=>{
const responseJson = {status: 200, msg: '成功',data};
res.send((responseJson));
});
});
async function encrypt_wsgw(phone){
//需要加密的手机号
// const phone = '17770034789';
const encryptedPhone = encrypt.encrypt(phone);
// console.log('【 encryptedPhone】', encryptedPhone)
//十位随机字符串
let randomStr = ()=>{
let randomStr=""
for (var a = 0; a < 10; a++){
randomStr += Math.floor(10 * Math.random());
}
return randomStr
}
//上级账号信息
const urlData = {
"k1": "42132762122",
"k2": "f3100e73776g723019i7h0009f2ihi19",
"k3": "620000",
"k4": "620400",
"k5": "620402"
}
//参数数据组合
const t = {
validateInfo: JSON.stringify({
quInfo: {
k7: encryptedPhone,
accountType: "",
businessType: "saveuser",
sendType: "0"
},
uscInfo: {
devciceId: "868800020356147",
devciceIp: "192.168.1.1",
member: "2203",
tenant: "state_grid"
}
}),
tCode: randomStr(),
userInfo: JSON.stringify(urlData)
};
//node中base64编码
// let buff = new Buffer(JSON.stringify(t));
const buff = Buffer.from(JSON.stringify(t));// 默认用 utf-8 编码格式解释字符串
const base64data = buff.toString('base64');
// console.log('【 base64data】', base64data)
let data = `jsonString=${base64data}`
//需要加密发送的jsonString参数
// console.log('【 需要加密发送的jsonString参数】', data)
const config = {
method: 'post',
url: 'https://osg-static.sgcc.com.cn/osg-sfan0009/member/c7/f01',
headers: {
'Connection': 'keep-alive',
'Pragma': 'no-cache',
'Cache-Control': 'no-cache',
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'Origin': 'https://osg-static.sgcc.com.cn',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Dest': 'empty',
'Referer': 'https://osg-static.sgcc.com.cn/activity/reg/index.html?k1=42132762122&k2=f3100e73776g723019i7h0009f2ihi19&k3=620000&k4=620400&k5=620402',
'Accept-Language': 'zh-CN,zh;q=0.9'
},
data : data
};
async function requestSomething(){
await axios(config)
.then(function (response) {
// console.log(JSON.stringify(response.data));
//查询成功
if (response.data.code == 1) {
const {returnJson} = response.data.data;
const buf1 = Buffer.from(returnJson, 'base64');
console.log('【 text】', buf1.toString())
return decryptData = buf1.toString()
}
})
.catch(function (error) {
console.log(error);
});
return decryptData
}
return await requestSomething()
}
package.json
{
"name": "guowang",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.24.0",
"body-parser": "^1.19.1",
"express": "^4.17.2",
"node-jsencrypt": "^1.0.0"
}
}
1.端口可以自定义 2.npm i 直接安装所有依赖 3.node index.js 启动监听端口 前端或者直接api调用 拼接形式http://127.0.0.1:3001/search?phone=18770034781
三、linux服务器部署接口项目
在linux上部署最坑的是,忘记开防火墙了。对应端口的防火墙设置没有打开,导致一直请求不到对应的端口,获取不到返回数据
在自己的服务器上,查看防火墙,看一下是否添加了对应的端口规则,我就是在这被阻挡了半天,用postman死活调用不到这个api接口,最后排查,是这个端口没开放,被防火墙拦住了。引以为鉴。
部署,最好安装一个pm2 这样在你终端关掉,之后,服务也会正常使用。
npm i -g pm2
把你的项目除node_modules目录外,全部上传到你指定的目录路径,然后npm i 重装依赖 pm2 start index.js即可 要记得,执行此命令要在当前文件目录下才行。
至此,你就将整个项目从浏览器搬到了自己的服务器上,并使用node编写后端。