aslan-h5/docs/security/atu-prod-hardening-playbook.zh-CN.md
2026-04-21 16:42:29 +08:00

362 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# `atu-prod` 分支前端加固迁移执行手册
## 目的
这份文档用于在后续切换到 `atu-prod` 分支后,按固定步骤复用当前分支已经落地的前端防扒取加固方案。
使用方式很简单:
- 当你切到 `atu-prod` 后,只要说明“按 `atu-prod-hardening-playbook.zh-CN.md` 执行”
- 我就按这份文档中的顺序检查、迁移、修复和验证
这份文档不是泛泛的说明,而是面向实际执行的作业手册。
## 适用前提
- `atu-prod` 分支与当前分支在业务功能上大体一致
- 主要差异集中在样式、布局、局部结构命名
- 活动页和榜单页的核心交互、接口、资源使用方式基本相同
如果后续发现 `atu-prod` 在页面结构上差异很大,这份手册仍然能作为基线,但执行时要允许局部调整。
## 迁移目标
切换到 `atu-prod` 后,需要尽量恢复当前分支已经完成的这些能力:
1. 受保护页面仅允许在 App 环境下访问
2. 运行时基础防调试、防复制、防拖拽和动态水印
3. `Activities / Ranking` 图片地址保护与运行时解析
4. `background-image` 相关真实图链泄露点收口
5. 构建产物哈希化和可读性降低
6. 生产相关模式日志清理与保留日志开关
7. `v-show``v-if` 的主内容延迟挂载改造
8. `BackgroundLayer``useCanvas` 背景合成方案
9. 明显语义类名收口
10. 已发现问题页的修复和清理
## 执行顺序
后续在 `atu-prod` 分支执行时,按下面顺序做,不要跳步。
### 第 1 步:先对照基础能力文件
优先检查这些全局能力文件是否已经存在、是否需要同步:
- [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)
- [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)
- [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)
- [src/components/BackgroundLayer.vue](/D:/programs/likei-h5/src/components/BackgroundLayer.vue)
- [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)
这一步的目标是先把“全局基础设施”对齐,再进页面级迁移。
### 第 2 步:扫描 `Activities / Ranking` 页面
重点扫描这两个目录:
- [src/views/Activities](/D:/programs/likei-h5/src/views/Activities)
- [src/views/Ranking](/D:/programs/likei-h5/src/views/Ranking)
执行时重点看四类点:
1. 是否仍有大量直接 `<img :src="getPngUrl(...)" />`
2. 是否仍有 `background-image: url(...)`
3. 是否存在 `v-show="!isLoading"` 控制主内容
4. 是否存在明显语义类名、明显业务含义 chunk 入口、测试日志
### 第 3 步:优先迁移高风险页面
后续在 `atu-prod` 中优先处理这些已经确认过风险较高、且当前分支已加固的页面:
- [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/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/Activities/SpringFestival/Task.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/Task.vue)
- [src/views/Ranking/Couple/index.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/index.vue)
- [src/views/Ranking/Couple/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/Ranking.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)
## 页面级迁移检查清单
后续每处理一个页面,都按这份清单检查。
### A. 图片链路
- 是否统一通过 `getPngUrl()` / `getWebpUrl()` 走受保护地址
- 是否尽量使用 `v-smart-img`
- 是否存在直接暴露真实 OSS 地址的模板位点
- 是否存在必须保留的 CSS 背景图场景
### B. 背景层
- 页面背景是否可改成 [BackgroundLayer.vue](/D:/programs/likei-h5/src/components/BackgroundLayer.vue)
- 如果是多层纯装饰背景,是否开启 `:useCanvas="true"`
- 如果只是普通内容图,不强制改成 canvas
说明:
- `useCanvas` 不应一刀切设成默认值 `true`
- 它只针对敏感背景层启用,避免把普通页面也全部切到更重的渲染路径
### C. 主内容挂载时机
- 页面是否仍使用 `v-show="!isLoading"` 控制主内容
- 如果页面存在预加载和监听时序问题,优先改成 `v-if="!isLoading"`
- 如果页面依赖 `IntersectionObserver`,应在 `await nextTick()` 后再注册
- 如果预加载可能失败,确保在 `finally` 中放行主内容,避免整页空白
### D. 语义暴露
- 是否有过于直白的局部类名
- 是否有业务含义明显的本地变量名或测试痕迹
- 是否有无用日志、调试文案、历史残留注释
### E. 组件生命周期
- `IntersectionObserver` 是否在卸载时 `disconnect()`
- 定时器是否在卸载时清理
- 残留监听代码是否已经失效却未移除
## 已知问题与处理记录
后续迁到 `atu-prod` 时,优先留意这些已经踩过的坑。
### 1. `v-show` 会让主内容 DOM 提前暴露
现象:
- 页面还在预加载时DOM 已经被挂载
- 容易被直接从 `Elements` 面板里抄结构
- 某些触底监听也会因为节点时序问题失灵
处理方式:
- 将主内容改为 `v-if="!isLoading"`
- 对依赖监听的组件,在 `nextTick()` 后注册观察器
-`finally` 中放行主内容
涉及页面:
- `LoginReward`
- `LuckyDollars/Season4`
- `SpringFestival`
- `Ranking/Couple`
- `Ranking/Overall`
### 2. `IntersectionObserver` 挂载时机不稳
现象:
- 监听节点存在,但绑定太早
- 页面结构还没稳定时就执行 `observe()`
- 页面切走后观察器残留
处理方式:
- `await nextTick()`
-`observer.observe(...)`
- `onUnmounted``disconnect()`
重点页面:
- [src/views/Activities/SpringFestival/Ranking.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/Ranking.vue)
### 3. `Ranking/Couple/Ranking.vue` 曾有残留无效加载监听代码
现象:
- 组件里保留了已经取消的加载模块逻辑
- 相关 `ref` 节点已不存在,但监听代码还在
处理方式:
- 清理失效的 `IntersectionObserver` 逻辑
- 删除无效加载模块相关变量
- 保留当前真实在用的数据展示逻辑
### 4. `Ranking/Couple/Ranking.vue` 曾出现乱码注释
现象:
- 早期编辑和编码处理后,中文注释出现乱码
处理方式:
- 清理乱码注释
- 统一改为中文注释
- 保持逻辑不变,只修复可读性
### 5. `BackgroundLayer` 为什么不是默认 `useCanvas=true`
结论:
- 因为它是公共组件
- 默认全开会把所有背景层都切到 canvas 路径
- 会增加普通页面的图片加载、重绘和兼容风险
当前策略:
- 只在高风险的 `Activities / Ranking` 页面显式传入 `:useCanvas="true"`
### 6. `toCssBackgroundImage()` 的作用
结论:
- 它不是加密层
- 它是把 `likei-protected:` 地址还原成 CSS 可用的 `url(...)`
- 主要用于必须保留 `background-image` 的点位
相关文件:
- [src/utils/protectedAssets.js](/D:/programs/likei-h5/src/utils/protectedAssets.js)
## 构建与验证步骤
### 基础构建
执行:
```bash
npm run build
```
预期:
- 构建成功
- 保留已知提示,但不新增本轮改动引起的报错
### 生产态验证
执行:
```bash
npm run dev:prod
```
或:
```bash
npm run build
npm run preview
```
验证点:
- 非 App 环境访问受保护页会被拦截
- 公共页可正常打开
- `Activities / Ranking` 页面的图片仍能显示
- `BackgroundLayer` 的 canvas 背景仍能正常渲染
- 触底加载和倒计时逻辑不受影响
### 日志构建验证
执行:
```bash
npm run build:prod
npm run build:prod:logs
npm run build:atu-prod
npm run build:atu-prod:logs
```
验证点:
- 默认生产相关包清理 `console.log``console.debug``console.info``debugger`
-`:logs` 的命令仍保留调试日志,便于 App 内定位问题
- Jenkins 使用原有命令不需要改发布流程
## 建议的迁移方法
后续切到 `atu-prod` 后,建议按下面方式推进:
1. 先同步全局基础能力文件
2. 再扫描 `Activities / Ranking`
3. 先迁移高风险页面
4. 每迁移一页就做局部验证
5. 最后统一跑 `npm run build`
6. 再补文档同步
## 后续文档同步方法
如果后续主分支继续更新了这些安全文档,想把最新 md 同步到当前分支,不需要再手工复制。
先决条件:
- 主分支上的文档更新已经提交到 Git
- 当前已经切换到目标分支,例如 `atu_prod`
执行命令:
```bash
npm run docs:sync:security -- master
```
如果你想从远端主分支同步,也可以用:
```bash
npm run docs:sync:security -- origin/master
```
这条命令会同步这些文件:
- `docs/security/frontend-hardening.md`
- `docs/security/frontend-hardening.zh-CN.md`
- `docs/security/frontend-hardening.zh-CN.updates.md`
- `docs/security/atu-prod-hardening-playbook.zh-CN.md`
对应脚本文件:
- [scripts/sync-security-docs.js](/D:/programs/likei-h5/scripts/sync-security-docs.js)
注意:
- 如果源分支里还没有提交这些 md脚本会直接报错
- 所以推荐流程是“先在主分支提交文档,再切到目标分支执行同步命令”
## 文档同步要求
后续在 `atu-prod` 做迁移时,文档也要同步更新,至少包含:
- 本次迁移到 `atu-prod` 的实际范围
- 哪些页面已迁移
- 哪些页面因结构差异暂未迁移
- 新遇到的问题和处理方式
- 最终验证结果
建议优先更新这些文档:
- [docs/security/frontend-hardening.zh-CN.md](/D:/programs/likei-h5/docs/security/frontend-hardening.zh-CN.md)
- [docs/security/frontend-hardening.zh-CN.updates.md](/D:/programs/likei-h5/docs/security/frontend-hardening.zh-CN.updates.md)
- [docs/security/atu-prod-hardening-playbook.zh-CN.md](/D:/programs/likei-h5/docs/security/atu-prod-hardening-playbook.zh-CN.md)
## 后续对我下指令的推荐说法
后续你切到 `atu-prod` 分支后,可以直接这样说:
-`atu-prod-hardening-playbook.zh-CN.md` 执行一遍
- 先按手册同步全局加固能力,再扫描 `Activities / Ranking`
- 按手册把高风险页面优先迁移,并同步更新文档
看到这类指令后,我默认会:
- 先核对分支当前状态
- 再按这份文档逐项执行
- 遇到结构差异时在不偏离目标的前提下做适配
- 最后把实际执行结果写回文档