268 lines
11 KiB
Markdown
268 lines
11 KiB
Markdown
# 前端加固说明
|
|
|
|
## 目的
|
|
|
|
这份文档用于记录当前主分支已经落地的前端防扒取加固方案。
|
|
|
|
核心目标是提高扒图、抄页面、低成本复刻的门槛,而不是宣称“前端已经绝对防住”。
|
|
|
|
## 范围
|
|
|
|
本次加固严格限制在当前前端项目内完成,不依赖:
|
|
|
|
- 后端接口改造
|
|
- 私有 OSS
|
|
- 短时签名 URL
|
|
- 服务端动态出图
|
|
|
|
## 已落地能力
|
|
|
|
### 1. 受保护页面访问限制
|
|
|
|
生产相关模式下,受保护页面要求运行在官方 App 环境中。
|
|
|
|
主要文件:
|
|
|
|
- [src/utils/routeGuard.js](/D:/programs/likei-h5/src/utils/routeGuard.js)
|
|
- [src/utils/http.js](/D:/programs/likei-h5/src/utils/http.js)
|
|
- [src/config/security.js](/D:/programs/likei-h5/src/config/security.js)
|
|
|
|
表现:
|
|
|
|
- 公共页面仍可正常访问
|
|
- 受保护页面在非 App 环境下会跳转到 `/#/not_app`
|
|
- 受保护页面内的接口请求在缺少 App bridge 时会被拒绝
|
|
|
|
### 2. 运行时防调试与防复制限制
|
|
|
|
对受保护页面增加了一层轻量运行时限制。
|
|
|
|
主要文件:
|
|
|
|
- [src/utils/runtimeSecurity.js](/D:/programs/likei-h5/src/utils/runtimeSecurity.js)
|
|
- [src/main.js](/D:/programs/likei-h5/src/main.js)
|
|
- [src/App.vue](/D:/programs/likei-h5/src/App.vue)
|
|
|
|
表现:
|
|
|
|
- 屏蔽常见开发者工具快捷键
|
|
- 屏蔽右键、拖拽、复制、文本选择等交互
|
|
- 降低长按保存图片的便利性
|
|
|
|
### 3. `Activities` / `Ranking` 图片受保护地址层
|
|
|
|
`Activities/` 和 `Ranking/` 目录下的大部分图片,不再直接以真实 OSS 地址出现在模板中。
|
|
|
|
主要文件:
|
|
|
|
- [src/config/imagePaths.js](/D:/programs/likei-h5/src/config/imagePaths.js)
|
|
- [src/utils/protectedAssets.js](/D:/programs/likei-h5/src/utils/protectedAssets.js)
|
|
- [src/utils/protectedAssetRuntime.js](/D:/programs/likei-h5/src/utils/protectedAssetRuntime.js)
|
|
- [src/directives/smartImage.js](/D:/programs/likei-h5/src/directives/smartImage.js)
|
|
- [src/utils/image/imageCacheManager.js](/D:/programs/likei-h5/src/utils/image/imageCacheManager.js)
|
|
|
|
表现:
|
|
|
|
- `getPngUrl()` / `getWebpUrl()` 会先输出 `likei-protected:...`
|
|
- 运行时只有在真正渲染时才解析成真实地址
|
|
- 大部分图片最终会走缓存并转换成 blob/object URL
|
|
- 即使个别页面漏了 `v-smart-img`,运行时也有兜底解析
|
|
|
|
### 4. `background-image` 泄露点补丁
|
|
|
|
部分重点页面之前通过内联 `background-image: url(...)` 直接暴露真实地址,这类点位已经做了兼容收口。
|
|
|
|
已调整文件:
|
|
|
|
- [src/views/Activities/LesserBairam/index.vue](/D:/programs/likei-h5/src/views/Activities/LesserBairam/index.vue)
|
|
- [src/views/Activities/LuckyDollars/Season3/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season3/index.vue)
|
|
- [src/views/Activities/SpringFestival/index.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/index.vue)
|
|
- [src/views/Activities/SpringFestival/Task.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/Task.vue)
|
|
- [src/views/Ranking/KingAndQueen/TopList.vue](/D:/programs/likei-h5/src/views/Ranking/KingAndQueen/TopList.vue)
|
|
|
|
表现:
|
|
|
|
- 写入 CSS 前先通过受保护地址辅助方法解析
|
|
- 模板和样式字符串里直接出现真实图链的情况更少
|
|
|
|
### 5. 构建产物可读性降低
|
|
|
|
构建输出文件名从可读页面名改成了哈希命名。
|
|
|
|
主要文件:
|
|
|
|
- [vite.config.js](/D:/programs/likei-h5/vite.config.js)
|
|
|
|
表现:
|
|
|
|
- JS chunk 文件名不再直接暴露 `TopList`、`WeeklyStar`、`Ranking` 等页面名
|
|
- CSS 文件名也改为哈希命名
|
|
- 静态资源文件名同样使用哈希
|
|
|
|
### 6. 生产包自动清理日志,并保留可切换开关
|
|
|
|
生产相关打包模式下,会自动清掉常见调试日志;同时保留一个方便排查 App 内问题的“保留日志”构建开关。
|
|
|
|
主要文件:
|
|
|
|
- [vite.config.js](/D:/programs/likei-h5/vite.config.js)
|
|
- [package.json](/D:/programs/likei-h5/package.json)
|
|
- [scripts/build-with-version.js](/D:/programs/likei-h5/scripts/build-with-version.js)
|
|
|
|
表现:
|
|
|
|
- `production` 下自动移除 `console.log`
|
|
- `production` 下自动移除 `console.debug`
|
|
- `production` 下自动移除 `console.info`
|
|
- 生产相关模式下自动移除 `debugger`
|
|
- `console.warn` 和 `console.error` 保留,方便线上排查
|
|
- Jenkins 仍可继续使用原有默认打包命令
|
|
|
|
常用命令:
|
|
|
|
```bash
|
|
npm run build:prod
|
|
npm run build:prod:logs
|
|
```
|
|
|
|
### 7. 部分高风险页面改为延迟挂载主内容 DOM
|
|
|
|
部分活动页和榜单页原来使用 `v-show="!isLoading"` 控制主内容,这会让完整 DOM 树在较早阶段就已经挂载出来,也容易和 `IntersectionObserver` 的注册时序冲突。
|
|
|
|
现在这几页已经改成 `v-if="!isLoading"` 再挂载主内容:
|
|
|
|
- [src/views/Activities/LoginReward/index.vue](/D:/programs/likei-h5/src/views/Activities/LoginReward/index.vue)
|
|
- [src/views/Activities/LuckyDollars/Season4/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season4/index.vue)
|
|
- [src/views/Activities/SpringFestival/index.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/index.vue)
|
|
- [src/views/Ranking/Couple/index.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/index.vue)
|
|
- [src/views/Ranking/Overall/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Overall/Ranking.vue)
|
|
|
|
同步补了两类兜底:
|
|
|
|
- 对依赖 `IntersectionObserver` 的页面,在 `await nextTick()` 之后再注册观察器
|
|
- 预加载结束逻辑仍然放在 `finally` 中,避免预加载失败时页面长期空白
|
|
|
|
### 8. 装饰背景堆图改为可选 canvas 渲染
|
|
|
|
公共背景组件现在支持可选的 canvas 渲染模式,适合处理活动页和榜单页那种“纯装饰背景层层堆图”的场景。
|
|
|
|
主要文件:
|
|
|
|
- [src/components/BackgroundLayer.vue](/D:/programs/likei-h5/src/components/BackgroundLayer.vue)
|
|
|
|
当前已接入的高风险页面:
|
|
|
|
- [src/views/Activities/LesserBairam/index.vue](/D:/programs/likei-h5/src/views/Activities/LesserBairam/index.vue)
|
|
- [src/views/Activities/LoginReward/index.vue](/D:/programs/likei-h5/src/views/Activities/LoginReward/index.vue)
|
|
- [src/views/Activities/LuckyDollars/Season3/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season3/index.vue)
|
|
- [src/views/Ranking/Couple/index.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/index.vue)
|
|
- [src/views/Activities/LuckyDollars/Season4/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season4/index.vue)
|
|
- [src/views/Activities/SpringFestival/index.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/index.vue)
|
|
- [src/views/Ranking/GamesKing/index.vue](/D:/programs/likei-h5/src/views/Ranking/GamesKing/index.vue)
|
|
- [src/views/Ranking/KingAndQueen/TopList.vue](/D:/programs/likei-h5/src/views/Ranking/KingAndQueen/TopList.vue)
|
|
- [src/views/Ranking/Overall/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Overall/Ranking.vue)
|
|
- [src/views/Ranking/WeeklyStar/WeeklyStar.vue](/D:/programs/likei-h5/src/views/Ranking/WeeklyStar/WeeklyStar.vue)
|
|
|
|
表现:
|
|
|
|
- 多张纯装饰背景图会先合成到单个 canvas 中,而不是在 DOM 里直接挂一个个 `<img>`
|
|
- 从 Elements 面板直接看页面背景结构会比之前更不直观
|
|
- 受保护图片地址仍然继续走现有的运行时解析和缓存链路
|
|
|
|
### 9. 生产构建混淆再收紧,并补一轮明显语义类名收口
|
|
|
|
生产相关构建模式现在显式开启更严格的 `esbuild` 压缩参数,同时针对重点页面收了一轮最显眼的本地类名。
|
|
|
|
主要文件:
|
|
|
|
- [vite.config.js](/D:/programs/likei-h5/vite.config.js)
|
|
- [src/views/Ranking/Couple/index.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/index.vue)
|
|
- [src/views/Activities/LuckyDollars/Season4/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season4/index.vue)
|
|
- [src/views/Activities/SpringFestival/index.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/index.vue)
|
|
- [src/views/Activities/SpringFestival/Ranking.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/Ranking.vue)
|
|
- [src/views/Ranking/Overall/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Overall/Ranking.vue)
|
|
- [src/views/Ranking/WeeklyStar/WeeklyStar.vue](/D:/programs/likei-h5/src/views/Ranking/WeeklyStar/WeeklyStar.vue)
|
|
|
|
### 10. `Ranking/Couple` 注释修复与背景组件说明补充
|
|
|
|
近期对 [src/views/Ranking/Couple/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/Ranking.vue) 做了一次编码与注释清理:
|
|
|
|
- 清除了上一次编辑中遗留的乱码注释
|
|
- 将核心业务注释统一收口为中文,便于后续维护
|
|
|
|
同时补充说明两个容易混淆的背景层工具点:
|
|
|
|
- [src/components/BackgroundLayer.vue](/D:/programs/likei-h5/src/components/BackgroundLayer.vue) 的 `useCanvas` 是显式开关,不默认全局开启
|
|
- [src/utils/protectedAssets.js](/D:/programs/likei-h5/src/utils/protectedAssets.js) 中的 `toCssBackgroundImage()` 用于把 `likei-protected:` 地址还原成 CSS 可用的 `background-image: url(...)`
|
|
|
|
## 这套方案能挡住什么
|
|
|
|
当前前端加固,对以下场景有一定抬门槛作用:
|
|
|
|
- 普通浏览器直接打开受保护页面
|
|
- 低门槛 DOM 抓取
|
|
- 从模板或页面源码里直接抄图片地址
|
|
- 从可读的构建产物文件名里反推页面用途
|
|
- 简单右键、拖拽、长按保存
|
|
- 依赖“页面初始 DOM 直接可见”的低成本抄结构方式
|
|
|
|
## 当前边界
|
|
|
|
这套改动依然无法彻底防住以下情况:
|
|
|
|
- 通过 Network 面板或抓包获取图片请求
|
|
- 有经验的人持续分析前端运行时代码
|
|
- 自定义 WebView、自动化脚本、Hook 等方式截获资源
|
|
- 仅凭视觉观察后重新临摹布局和样式
|
|
- 从本来就被允许渲染页面的客户端中提取 DOM、CSS、JS
|
|
|
|
只要客户端能把页面渲染出来,客户端就一定拿到了足够还原页面的信息。
|
|
|
|
## 推荐测试方式
|
|
|
|
### 受保护页面拦截
|
|
|
|
可使用:
|
|
|
|
```bash
|
|
npm run dev:prod
|
|
```
|
|
|
|
或:
|
|
|
|
```bash
|
|
npm run build
|
|
npm run preview
|
|
```
|
|
|
|
预期结果:
|
|
|
|
- 非 App 环境下访问受保护页面会跳转到 `/#/not_app`
|
|
- 公共页面仍可正常访问
|
|
|
|
### 页面与图片链路验证
|
|
|
|
在接近生产环境的模式下检查:
|
|
|
|
- `Activities` / `Ranking` 页面是否仍能正常展示
|
|
- 受保护图片是否仍能正常显示
|
|
- 运行时 DOM 和构建产物里是否更少直接暴露真实图链
|
|
- 本次从 `v-show` 切到 `v-if` 的页面,是否仍能在预加载结束后正常渲染
|
|
- 依赖触底加载的页面,滚动加载是否仍然正常
|
|
|
|
### 构建产物验证
|
|
|
|
执行:
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
预期结果:
|
|
|
|
- `dist/js` 文件名以哈希为主
|
|
- `dist/css` 文件名以哈希为主
|
|
- 构建产物文件名中不再直观出现页面名
|
|
- 生产包中不再保留 `console.log`、`console.debug`、`console.info` 和 `debugger`
|
|
|