aslan-h5/docs/security/frontend-hardening.zh-CN.md
2026-04-21 18:23:45 +08:00

11 KiB

前端加固说明

目的

这份文档用于记录当前主分支已经落地的前端防扒取加固方案。

核心目标是提高扒图、抄页面、低成本复刻的门槛,而不是宣称“前端已经绝对防住”。

范围

本次加固严格限制在当前前端项目内完成,不依赖:

  • 后端接口改造
  • 私有 OSS
  • 短时签名 URL
  • 服务端动态出图

已落地能力

1. 受保护页面访问限制

生产相关模式下,受保护页面要求运行在官方 App 环境中。

主要文件:

表现:

  • 公共页面仍可正常访问
  • 受保护页面在非 App 环境下会跳转到 /#/not_app
  • 受保护页面内的接口请求在缺少 App bridge 时会被拒绝

2. 运行时防调试与防复制限制

对受保护页面增加了一层轻量运行时限制。

主要文件:

表现:

  • 屏蔽常见开发者工具快捷键
  • 屏蔽右键、拖拽、复制、文本选择等交互
  • 降低长按保存图片的便利性

3. Activities / Ranking 图片受保护地址层

Activities/Ranking/ 目录下的大部分图片,不再直接以真实 OSS 地址出现在模板中。

主要文件:

表现:

  • getPngUrl() / getWebpUrl() 会先输出 likei-protected:...
  • 运行时只有在真正渲染时才解析成真实地址
  • 大部分图片最终会走缓存并转换成 blob/object URL
  • 即使个别页面漏了 v-smart-img,运行时也有兜底解析

4. background-image 泄露点补丁

部分重点页面之前通过内联 background-image: url(...) 直接暴露真实地址,这类点位已经做了兼容收口。

已调整文件:

表现:

  • 写入 CSS 前先通过受保护地址辅助方法解析
  • 模板和样式字符串里直接出现真实图链的情况更少

5. 构建产物可读性降低

构建输出文件名从可读页面名改成了哈希命名。

主要文件:

表现:

  • JS chunk 文件名不再直接暴露 TopListWeeklyStarRanking 等页面名
  • CSS 文件名也改为哈希命名
  • 静态资源文件名同样使用哈希

6. 生产包自动清理日志,并保留可切换开关

生产相关打包模式下,会自动清掉常见调试日志;同时保留一个方便排查 App 内问题的“保留日志”构建开关。

主要文件:

表现:

  • production 下自动移除 console.log
  • production 下自动移除 console.debug
  • production 下自动移除 console.info
  • 生产相关模式下自动移除 debugger
  • console.warnconsole.error 保留,方便线上排查
  • Jenkins 仍可继续使用原有默认打包命令

常用命令:

npm run build:prod
npm run build:prod:logs

7. 部分高风险页面改为延迟挂载主内容 DOM

部分活动页和榜单页原来使用 v-show="!isLoading" 控制主内容,这会让完整 DOM 树在较早阶段就已经挂载出来,也容易和 IntersectionObserver 的注册时序冲突。

现在这几页已经改成 v-if="!isLoading" 再挂载主内容:

同步补了两类兜底:

  • 对依赖 IntersectionObserver 的页面,在 await nextTick() 之后再注册观察器
  • 预加载结束逻辑仍然放在 finally 中,避免预加载失败时页面长期空白

8. 装饰背景堆图改为可选 canvas 渲染

公共背景组件现在支持可选的 canvas 渲染模式,适合处理活动页和榜单页那种“纯装饰背景层层堆图”的场景。

主要文件:

当前已接入的高风险页面:

表现:

  • 多张纯装饰背景图会先合成到单个 canvas 中,而不是在 DOM 里直接挂一个个 <img>
  • 从 Elements 面板直接看页面背景结构会比之前更不直观
  • 受保护图片地址仍然继续走现有的运行时解析和缓存链路

9. 生产构建混淆再收紧,并补一轮明显语义类名收口

生产相关构建模式现在显式开启更严格的 esbuild 压缩参数,同时针对重点页面收了一轮最显眼的本地类名。

主要文件:

10. Ranking/Couple 注释修复与背景组件说明补充

近期对 src/views/Ranking/Couple/Ranking.vue 做了一次编码与注释清理:

  • 清除了上一次编辑中遗留的乱码注释
  • 将核心业务注释统一收口为中文,便于后续维护

同时补充说明两个容易混淆的背景层工具点:

这套方案能挡住什么

当前前端加固,对以下场景有一定抬门槛作用:

  • 普通浏览器直接打开受保护页面
  • 低门槛 DOM 抓取
  • 从模板或页面源码里直接抄图片地址
  • 从可读的构建产物文件名里反推页面用途
  • 简单右键、拖拽、长按保存
  • 依赖“页面初始 DOM 直接可见”的低成本抄结构方式

当前边界

这套改动依然无法彻底防住以下情况:

  • 通过 Network 面板或抓包获取图片请求
  • 有经验的人持续分析前端运行时代码
  • 自定义 WebView、自动化脚本、Hook 等方式截获资源
  • 仅凭视觉观察后重新临摹布局和样式
  • 从本来就被允许渲染页面的客户端中提取 DOM、CSS、JS

只要客户端能把页面渲染出来,客户端就一定拿到了足够还原页面的信息。

推荐测试方式

受保护页面拦截

可使用:

npm run dev:prod

或:

npm run build
npm run preview

预期结果:

  • 非 App 环境下访问受保护页面会跳转到 /#/not_app
  • 公共页面仍可正常访问

页面与图片链路验证

在接近生产环境的模式下检查:

  • Activities / Ranking 页面是否仍能正常展示
  • 受保护图片是否仍能正常显示
  • 运行时 DOM 和构建产物里是否更少直接暴露真实图链
  • 本次从 v-show 切到 v-if 的页面,是否仍能在预加载结束后正常渲染
  • 依赖触底加载的页面,滚动加载是否仍然正常

构建产物验证

执行:

npm run build

预期结果:

  • dist/js 文件名以哈希为主
  • dist/css 文件名以哈希为主
  • 构建产物文件名中不再直观出现页面名
  • 生产包中不再保留 console.logconsole.debugconsole.infodebugger