Skip to content

Commit

Permalink
chore: fix typos
Browse files Browse the repository at this point in the history
  • Loading branch information
kuizuo committed Sep 20, 2023
1 parent 8126e4b commit 1f4331c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 41 deletions.
56 changes: 23 additions & 33 deletions blog/develop/模拟请求 协议复现方案.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,24 @@ keywords: [http, protocol]
description: 模拟请求/协议复现 最佳实践方案
---

前段时间看了别人的一个写了羊了个羊刷次数网页版,但是 js 代码做了混淆,然后我的那个解混淆的工具还没适配上,短时间内还原不了。但由于是网页版,所以抓包数据还是能看到的,于是就准备复刻了一个(其实就没有也照样能写出来,因为确实没啥难度)
前段时间看了别人的一个写了羊了个羊刷次数网页版,但是 js 代码做了混淆,然后我的那个解混淆的工具还没适配上,短时间内还原不了。但由于是网页版,所以抓包数据还是能看到的,于是就准备复刻了一个。

可在此体验:[7y8y.vercel.app](https://7y8y.vercel.app) (当然由于官方改动,现在功能已经失效了,但看看页面到不成问题,可能需要科学上网)

原本我是不考虑写的,但是这背后所涉及到的技术以及技术框架我是特别想聊聊,加之以后我也有很大的可能会再写一个类似的刷 xx 的网页版,所以就考虑写一个类似的模板以便后续应用需求。

相关模板:[https://github.com/kuizuo/protocol](https://github.com/kuizuo/protocol)

与此同时,我也快有半年的时间没碰**协议复现**(网络通信协议重新实现,后文都简称协议复现)。我更喜欢说这个词,也有的人会说**模拟请求**,对应的关键词可能有 post 请求,抓包,发包,爬虫等等,但大致的意思是**抓取请求数据包,然后脱离宿主机(浏览器,手机),将抓取的数据包重新发送一遍**
与此同时,我也快有半年的时间没碰 **协议复现**(网络通信协议重新实现,后文都简称协议复现)。我更喜欢说这个词,也有的人会说**模拟请求**,对应的关键词可能有 post 请求,抓包,发包,爬虫等等,但大致的意思是**抓取请求数据包,然后脱离宿主机(浏览器,手机),将抓取的数据包重新发送一遍**

你也可以理解成爬虫,但和爬虫相比,要做的不只是爬取数据,而是要基于某些请求包(或者说调用他人不提供的 api 接口,即爬取),来实现一定的功能。比如登录协议,签到协议,抢购协议,游戏封包等等,然后不依靠宿主机(即不用登录浏览器或者应用设备)就能实现诸如登录,签到等功能(在后台记录是有的)。因为这些都是基于网络通信协议的,只要抓包(抓取数据包),然后使用编程提供的网络请求模块来模拟请求,达到重新发包,重新请求的目的。在网页中有 http 协议,websocket 协议,而游戏中有相应的与游戏服务器对应的协议,邮件短信文件又是不同的协议(这里的协议都叫网络通信协议),所以我个人更倾向于称之为协议复现。

所以要做协议复现,那基本上有一定的逆向功底和爬虫能力,还有网络通信协议相关的知识了。此次的开发也算是回顾下这些相关技术了。

:::danger

注:**本项目仅用于学习研究使用,请勿将本项目的任何内容用于商业或非法目的,否则后果自负。**

:::

<!-- truncate -->

在这里容我多废话几句,讲一个我之前的开发经历,可以说这个开发经历算是这篇文章的由来。

## 小区开门应用

在这里容我多废话几句,讲一个我之前的一次开发经历,可以说这次的开发经历算是这篇文章的由来。

### 应用需求

在之前住的一个小区,有个门禁系统,需要安装一个开门的 app(后文都称开门 app),然后注册一个账号到物业那边登记为户主或家庭成员。
Expand All @@ -42,29 +34,27 @@ description: 模拟请求/协议复现 最佳实践方案

于是我想的是将接口数据“偷”了过来,将大门列表展示在前端上,然后点击对应的大门,然后将大门 id 转发给原 app 的服务器,就实现了开门的效果,也就是这个小区开门的网页版的核心逻辑。

大致界面如下,展示小区的大门,点击即可开门(远程)
当时设计的界面大致如下,展示小区的大门,点击即可远程开门。

![](https://img.kuizuo.cn/image_Zv0hXU8h1j.png)

因为是网页版的,所以只需要在浏览器打开对应的网址,点击大门即可(主要还是这个 app 不提供桌面快捷方式,点击这个 app 还需要观看首屏广告,手机网页浏览器提供某个网站的快捷打开) 。此外他人也不用到物业登记,就能开门,对于一些朋友或者住户来说,省去了物业登记的繁琐。
因为是网页版的,所以只需要在浏览器打开对应的网址,点击对应的大门按钮即可。而开发的初衷是这个 app 不提供桌面快捷方式,点击这个 app 还需要观看首屏广告,此外他人也不用到物业登记,就能开门,对于一些朋友或者住户来说,省去了物业登记的繁琐。

不过这个软件还是有挺多要注意的点:首先就是鉴权了,由于我当时主要目的是为了我自己和身边朋友,网站也没有特意发布到互联网上,所以就没做鉴权相关的,不然正常情况下是一定要做鉴权和调用记录的,以及 ip 白名单的。否则搞不好登录原 app 的账号直接因为调用过于频繁直接给禁用了;最主要的安全问题,这里的安全可不只是网站的安全,而是现实的安全。想想如果有一个可以随意进出小区大门的程序,那么任何人都可以进入这个小区,小区的公共设施,业主生活质量安全等等谁来保障?而且最主要所绑定的账号还是我的,万一小区真出了事,那么我的责任将会非常大。

综合考量,这个应用是绝对不可能大肆发布到网上的。个人自用问题还是不大,因为这种调用量对服务器几乎没有什么压力。

我的初衷也仅仅只是因为作为开发者的我,**降低了我点击开门的频率,免去登记的繁琐。**

在当时我甚至想基于手机的 GPS 定位,来实现靠近小区自动开门。真羡慕当时我的一堆想法,但也遗憾当时没有去尝试实现这一个想法。

### 开发

这个应用就大致初衷就说到这了,接下来我要说说开发,这也就是本文说要的重点内容了。下面是我当时的项目结构:
这个应用的起源就说到这了,接下来我要说说其开发形态了,这也就是本文说要的重点内容了。下面是我当时的项目结构:

![](https://img.kuizuo.cn/image_7J7PhsdaQy.png)

不难看出,这是一个前后端分离的项目,其中前端使用 uniapp 来开发一套代码多端运行,并且使用的是 Hbuilder 编辑器来开发。而后端就是常规的 Node 后端服务,使用的是 Express 框架。

技术栈就介绍完毕,这里我要介绍整个流程
技术栈就介绍完毕,这里我要介绍整个开门实现流程

就说说获取大门列表和开门的两个接口请求:

Expand Down Expand Up @@ -112,12 +102,12 @@ router.get('/open', async (req, res, next) => {

这里的代码也仅仅只是作为演示,实际代码可不止这么简单,因为还需要涉及到登录,加密等等环节。

我的前端页面访问地址是 [http://localhost:5000](http://localhost:5000)我需要 [http://localhost:3000/api/list](http://localhost:3000/api/list)[http://localhost:3000/api/openDoor](http://localhost:3000/api/openDoor)
我的前端页面访问地址是 [http://localhost:5000](http://localhost:5000)我需要访问后端接口 [http://localhost:3000/api/list](http://localhost:3000/api/list)[http://localhost:3000/api/openDoor](http://localhost:3000/api/openDoor)

可能有些人会问,为啥要后端服务,不直接在前端向开门 app 的服务器发送请求,然后将响应直接渲染到前端上。比如直接在前端代码中写 openopenDoor 函数
对于不了解 web 开发的人员可能会问为啥要后端服务,不直接在前端向开门 app 的服务器发送请求,然后将响应直接渲染到前端上。比如直接在前端代码中写 openopenDoor 函数

```javascript
async function openDoor(id) => {
async function openDoor(id) {

// 模拟请求开门
let url = `https://xxx.com/api/openDoorControl`
Expand All @@ -131,11 +121,11 @@ async function openDoor(id) => {
})
```

这个疑惑在我初次想使用 web 端来实现协议复现的时候也考虑过,但浏览器不支持。这也是我下面所要说的
这个疑惑在我初次想使用 web 端来实现协议复现的时候也考虑过,但浏览器为了安全考虑而不支持。这也是我下面所要说的

### 同源策略 跨域

一般用户的浏览器是有非常强的页面安全策略的,这里要说的就是同源策略,更细分点就是跨域比如说 kuizuo.cn 这个站点,想要向 baidu.com 发送请求,请求是能够正常发送过去的,但是 kuizuo.cn 这个站点是接收不到任何数据。因为 kuizuo.cn 和 baidu.com 根本不是同一个网址,专业点说就是不同源,这种不同源的请求在浏览器,称为跨域请求。
一般用户的浏览器是有非常强的页面安全策略的,这里要说的就是同源策略,更细分点就是跨域比如说 kuizuo.cn 这个站点,想要向 baidu.com 发送请求,请求是能够正常发送过去的,但是 kuizuo.cn 这个站点是接收不到任何数据。因为 kuizuo.cn 和 baidu.com 根本不是同一个网址,专业点说就是不同源,这种不同源的请求在浏览器,称为跨域请求。

![](https://img.kuizuo.cn/image_QLEJFPTkb6.png)

Expand All @@ -148,21 +138,21 @@ access-control-allow-methods: GET, POST, PUT, DELETE, OPTIONS
access-control-allow-origin: *
```

浏览器会直接拒绝接收响应,但浏览器确实将请求发送给了服务端(打开控制台中的网络是看不到该请求的响应结果的)
浏览器会直接拒绝接收响应,**浏览器确实将请求发送给了服务端**,并且你打开控制台中的网络是看不到该请求的响应结果的

跨域限制只存在于浏览器端,在其他环境下是不存在,请求都是能够发送出去,并且是可以接收到的。所以说为什么不在前端直接向原应用程序的服务器发送请求,罪魁祸首也就是**同源策略**

### 不支持修改协议头

像 origin,reference,user-agents 等协议头是无法修改的
像 origin,reference,user-agents 等协议头在浏览器是无法修改的

```text
origin: https://xxx.com
referer: https://xxx.com/api/test
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.42
```

而有些请求是会效验你的设备信息,来源地址,这些内容在浏览器中都写在协议头中,且浏览器不支持修改。使用浏览器来发送数据,无疑就是告诉服务器我是浏览器发送的。服务器判断来源不是自家的域名,那就直接拒绝响应像防盗链就是检测 referer 。
而有些请求是会效验你的设备信息,来源地址,这些内容在浏览器中都写在协议头中,且浏览器不支持修改。使用浏览器来发送数据,无疑就是告诉服务器我是浏览器发送的。服务器判断来源不是自家的域名,那就直接拒绝响应像防盗链就是检测 referer 。

## 方案

Expand All @@ -174,7 +164,7 @@ user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,

这样的应用会有以下几点缺陷:

- **易破解**:由于你的大部分核心逻辑最终都会进行编译打包成 exe,如果会些破解技术,恰好你不做任何防护手段,要破解你的程序非常容易。所以也就为什么很多 exe 程序(尤其是易语言)会带有 .vmp.exe 也就是 vmp 加壳,让程序很难被分析与破解。并且我就可以开启系统抓包,就可以看到应用程序模拟发送的请求数据包是什么。
- **易破解**:由于你的大部分核心逻辑最终都会进行编译打包成 exe,如果会些破解技术,恰好你不做任何防护手段,要破解你的程序非常容易。所以也就为什么很多 exe 程序(尤其是易语言)会带有 `.vmp.exe` 后缀也就是 vmp 加壳,让程序很难被分析与破解。并且我就可以开启系统抓包,就可以看到应用程序模拟发送的请求数据包是什么。

- **不易跨平台**:大多数的协议复现都是 exe 桌面应用程序,虽然也有安卓,但一般比较少。对于非 windows 用户或者说手头不方便用电脑的用户就很难体验到,并且还要特意安装一个应用,应用程序更新也需要重新安装。

Expand Down Expand Up @@ -236,21 +226,21 @@ location /api/ {

最终选择那种开发方式还是取决对应的应用场景,没有绝对的方案,具体考虑哪种方案是需要考虑用户,代码安全,请求量,是否维护来考量了。

写到这,可能对大多数人而言还是不懂,也很正常,因为这些内容都不算属于传统开发的范畴,甚至可以说是做 hui 产的利
写到这,可能对大多数人而言还是不懂,也很正常,因为这些内容都不算属于传统开发的范畴,甚至可以说是做 <font color="gray">hui</font> 产的利器

## SSR 框架
## 全栈框架

我非常希望使用到浏览器的跨平台性,即多端运行,用户的设备只需要有一个浏览器能打开网页就能体验到。(这其实也算是我为什么学 web 开发的初衷了)

但是在一开始所介绍的小区开门应用中,这样的开发体验其实并不友好。因为我既要编写前端应用还要编写后端服务,相当于两个项目。同时部署应用和传统部署没有特别大的区别,都需要一台服务器,很多时候都是浪费在部署上。

而 SSR 框架可以算是后端应用开发和前端应用开发结合。能很好的解决上述存在的问题,并且也易于部署,下面我会细细道来。
而全栈框架可以算是后端应用开发和前端应用开发结合。能很好的解决上述存在的问题,并且也易于部署,下面我会细细道来。

这里我选用的 Nuxt3 框架,羊了个羊刷次数网页版就是基于 Nuxt3 框架来开发的,并且使用 vercel 来进行部署。我手头还写过一个项目 [api-service](https://github.com/kuizuo/api-service)
这里我选用的 [Nuxt](https://nuxt.com) 框架,这是一个基于 Vue 前端框架实现的服务端渲染框架,羊了个羊刷次数网页版就是基于 Nuxt3 框架来开发的,并且使用 vercel 来进行部署。我手头还写过一个项目 [api-service](https://github.com/kuizuo/api-service)

首先在 SSR 框架,是有对应的后端服务引擎。像 Nuxt3 使用的是 [Nitro](https://nitro.unjs.io/),而 Next.js 使用的是 koa。都提供了后端服务 API 的解决方案,同时这些都是服务都算是 `serverless function`(无服务函数),所以在编写与调用非常方便。
首先在全栈框架,是有对应的后端服务引擎。像 Nuxt 使用的是 [Nitro](https://nitro.unjs.io/),而 Next.js 使用的是 koa。都提供了后端服务 API 的解决方案,同时这些都是服务都算是 `serverless function`(无服务函数),所以在编写与调用非常方便。

此外基于 [Netlify](https://www.netlify.com/)[Vercel](https://vercel.com) 这些 `serverless development` 平台,可以非常方便的部署 SSR 框架。同时内置 CI/CD,只需要提交 git commit 就能实现自动构建自动部署。
此外基于 [Netlify](https://www.netlify.com/)[Vercel](https://vercel.com) 这些 `serverless development` 平台,可以非常方便的部署全栈框架。同时内置 CI/CD,只需要提交 git commit 就能实现自动构建自动部署。

最主要是的我恰好使用 Node.js 来做爬虫与 api 接口,因此后端复现接口也使用 js 来实现。

Expand Down
Loading

1 comment on commit 1f4331c

@vercel
Copy link

@vercel vercel bot commented on 1f4331c Sep 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

blog – ./

blog-kuizuo1.vercel.app
blog-git-main-kuizuo1.vercel.app
blog-kuizuo.vercel.app
kuizuo.cn

Please sign in to comment.