From 073c61e6bb79046486c9152ac9f06430ac5daf55 Mon Sep 17 00:00:00 2001
From: hzj <1304805162@qq.com>
Date: Tue, 21 Apr 2026 18:23:45 +0800
Subject: [PATCH] =?UTF-8?q?chore:=20=E5=8F=96=E6=B6=88=E5=8A=A8=E6=80=81?=
=?UTF-8?q?=E6=B0=B4=E5=8D=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../atu-prod-hardening-playbook.zh-CN.md | 361 ------------------
docs/security/frontend-hardening.md | 77 ++--
docs/security/frontend-hardening.zh-CN.md | 87 +----
.../frontend-hardening.zh-CN.updates.md | 54 +--
src/App.vue | 52 +--
5 files changed, 60 insertions(+), 571 deletions(-)
delete mode 100644 docs/security/atu-prod-hardening-playbook.zh-CN.md
diff --git a/docs/security/atu-prod-hardening-playbook.zh-CN.md b/docs/security/atu-prod-hardening-playbook.zh-CN.md
deleted file mode 100644
index e7dcdd6..0000000
--- a/docs/security/atu-prod-hardening-playbook.zh-CN.md
+++ /dev/null
@@ -1,361 +0,0 @@
-# `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. 是否仍有大量直接 `
`
-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`
-- 按手册把高风险页面优先迁移,并同步更新文档
-
-看到这类指令后,我默认会:
-
-- 先核对分支当前状态
-- 再按这份文档逐项执行
-- 遇到结构差异时在不偏离目标的前提下做适配
-- 最后把实际执行结果写回文档
diff --git a/docs/security/frontend-hardening.md b/docs/security/frontend-hardening.md
index 45a27da..b2aa852 100644
--- a/docs/security/frontend-hardening.md
+++ b/docs/security/frontend-hardening.md
@@ -2,20 +2,20 @@
## Purpose
-This document records the frontend-only hardening work added to this repository to raise the cost of scraping, asset reuse, and low-effort page reconstruction.
+This document records the frontend-only hardening currently applied on the main branch to raise the cost of scraping, asset reuse, and low-effort page reconstruction.
The goal is to make abuse less convenient, not to claim absolute protection.
## Scope
-All changes described here are limited to the frontend project.
+All changes described here stay within the frontend project.
-This work does not rely on:
+They do not rely on:
- backend API changes
- private OSS buckets
- signed image URLs
-- server-side watermark rendering
+- server-side image rewriting
## What Was Added
@@ -37,7 +37,7 @@ Behavior:
### 2. Runtime anti-debug and anti-copy restrictions
-Protected pages now add a lightweight runtime restriction layer in production-like modes.
+Protected pages add a lightweight runtime restriction layer in production-like modes.
Main files:
@@ -50,7 +50,6 @@ Behavior:
- blocks common devtools shortcuts
- blocks right-click, drag, copy, and text selection on protected pages
- reduces long-press image save convenience
-- adds page-level dynamic watermark overlays
### 3. Protected asset URL layer for `Activities` and `Ranking`
@@ -69,7 +68,7 @@ Behavior:
- `getPngUrl()` and `getWebpUrl()` emit `likei-protected:...`
- runtime code resolves protected URLs only when rendering is needed
- most image rendering flows now end up using cached blob/object URLs
-- even pages that missed `v-smart-img` still get a runtime fallback for protected image `src`
+- pages that missed `v-smart-img` still get a runtime fallback for protected image `src`
### 4. `background-image` compatibility fixes
@@ -102,11 +101,9 @@ Behavior:
- CSS files also use hash-based names
- static asset filenames are hash-based
-This does not stop reverse engineering, but it lowers the convenience of reading page structure from `dist/`.
-
### 6. Production log stripping with a troubleshooting switch
-Production-like builds strip common debug output, while still supporting a keep-logs build for app-side troubleshooting.
+Production-like builds strip common debug output while still supporting a keep-logs build for app-side troubleshooting.
Main files:
@@ -116,9 +113,9 @@ Main files:
Behavior:
-- `production` and `production-atu` builds remove `console.log`
-- `production` and `production-atu` builds remove `console.debug`
-- `production` and `production-atu` builds remove `console.info`
+- `production` builds remove `console.log`
+- `production` builds remove `console.debug`
+- `production` builds remove `console.info`
- production-like builds remove `debugger`
- `console.warn` and `console.error` are preserved
- Jenkins can keep using the original default build commands
@@ -128,8 +125,6 @@ Useful commands:
```bash
npm run build:prod
npm run build:prod:logs
-npm run build:atu-prod
-npm run build:atu-prod:logs
```
### 7. Deferred main DOM mounting for selected high-risk pages
@@ -148,15 +143,10 @@ Extra handling was added where needed:
- pages with `IntersectionObserver` targets now register observers only after `await nextTick()`
- preload completion still clears `isLoading` in `finally`, so preload failures do not leave the page permanently blank
-- this keeps the original lazy-load behavior more stable after switching from `v-show` to `v-if`
-
-Important limit:
-
-This is only a weak hardening step. It reduces early DOM exposure and makes initial inspection less direct, but it does not stop scraping once the page is fully rendered on the client.
### 8. Canvas-rendered decorative background stacks
-The shared background layer component now supports a canvas rendering mode for stacked background images.
+The shared background layer component supports a canvas rendering mode for stacked background images.
Main file:
@@ -181,11 +171,9 @@ Behavior:
- most page-level decorative background structure becomes less obvious in Elements inspection
- protected asset resolution still goes through the existing runtime/cache pipeline
-This does not hide the pixels from a determined attacker, but it reduces direct DOM readability and low-effort structure copying.
-
### 9. Stronger production minification and selector cleanup
-Production-like builds now use stricter `esbuild` minification flags, and a small set of highly readable page-local class names was reduced on sensitive pages.
+Production-like builds use stricter `esbuild` minification flags, and a small set of highly readable page-local class names was reduced on sensitive pages.
Main files:
@@ -197,13 +185,19 @@ Main files:
- [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` comment cleanup and helper clarification
+
+Recent cleanup also covered:
+
+- [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)
+- [src/utils/protectedAssets.js](/D:/programs/likei-h5/src/utils/protectedAssets.js)
+
Behavior:
-- production-like builds explicitly minify identifiers, syntax, and whitespace
-- legal comments are removed from build output
-- some obvious local selector names were replaced with shorter neutral names
-- selector cleanup now also covers obvious ranking navigation and history labels on additional `Activities` and `Ranking` pages
-- `SpringFestival/Ranking` now waits for `nextTick()` before observing its load sentinel and disconnects the observer on unmount
+- garbled comments in `Ranking/Couple/Ranking.vue` were cleaned up and unified into Chinese comments
+- `useCanvas` remains an explicit opt-in instead of becoming a global default
+- `toCssBackgroundImage()` stays as the CSS bridge for protected asset URLs
## What This Helps Against
@@ -226,11 +220,7 @@ These changes still do not fully prevent:
- rebuilding the same layout after visual inspection
- extracting DOM, CSS, and JS from any client that is allowed to render the page
-Important rule:
-
-If the client can render the page, the client must receive enough information to reproduce the page.
-
-That is why frontend-only hardening can only increase cost, not provide absolute protection.
+If the client can render the page, the client must receive enough information to reproduce it. Frontend-only hardening can only increase cost, not provide absolute protection.
## Recommended Testing
@@ -249,11 +239,6 @@ npm run build
npm run preview
```
-Expected:
-
-- protected routes redirect to `/#/not_app` outside the app
-- public routes still open normally
-
### Asset and page rendering checks
In production-like mode, verify:
@@ -279,17 +264,3 @@ Expected:
- no obvious page names appear in bundle filenames
- production bundles no longer retain `console.log`, `console.debug`, `console.info`, or `debugger`
-## Suggested Next Steps
-
-If staying frontend-only:
-
-- move more decorative shells from plain DOM/CSS into canvas rendering
-- reduce semantic structure in the most sensitive event pages
-- keep replacing remaining raw `background-image` and direct image flows with protected helpers
-
-If minimal backend support becomes acceptable later:
-
-- move sensitive OSS paths to private read
-- issue short-lived signed URLs
-- watermark sensitive images per user on the server side
-- validate app session or device identity before returning sensitive assets
diff --git a/docs/security/frontend-hardening.zh-CN.md b/docs/security/frontend-hardening.zh-CN.md
index ddd6f0f..22724f9 100644
--- a/docs/security/frontend-hardening.zh-CN.md
+++ b/docs/security/frontend-hardening.zh-CN.md
@@ -2,24 +2,18 @@
## 目的
-这份文档用于记录当前仓库内已经落地的前端侧防扒取、防复用加固方案。
+这份文档用于记录当前主分支已经落地的前端防扒取加固方案。
核心目标是提高扒图、抄页面、低成本复刻的门槛,而不是宣称“前端已经绝对防住”。
-如需在后续切换到 `atu-prod` 分支后复用整套处理,请直接参考:
-
-- [docs/security/atu-prod-hardening-playbook.zh-CN.md](/D:/programs/likei-h5/docs/security/atu-prod-hardening-playbook.zh-CN.md)
-
## 范围
-本次加固严格限制在当前前端项目内完成。
-
-当前方案不依赖:
+本次加固严格限制在当前前端项目内完成,不依赖:
- 后端接口改造
-- OSS 私有读
+- 私有 OSS
- 短时签名 URL
-- 服务端动态水印
+- 服务端动态出图
## 已落地能力
@@ -39,7 +33,7 @@
- 受保护页面在非 App 环境下会跳转到 `/#/not_app`
- 受保护页面内的接口请求在缺少 App bridge 时会被拒绝
-### 2. 运行时防调试、防复制与页面水印
+### 2. 运行时防调试与防复制限制
对受保护页面增加了一层轻量运行时限制。
@@ -54,7 +48,6 @@
- 屏蔽常见开发者工具快捷键
- 屏蔽右键、拖拽、复制、文本选择等交互
- 降低长按保存图片的便利性
-- 给受保护页面增加动态水印覆盖
### 3. `Activities` / `Ranking` 图片受保护地址层
@@ -77,7 +70,7 @@
### 4. `background-image` 泄露点补丁
-部分重点页面之前仍通过内联 `background-image: url(...)` 直接暴露真实地址,这类点位已经做了兼容收口。
+部分重点页面之前通过内联 `background-image: url(...)` 直接暴露真实地址,这类点位已经做了兼容收口。
已调整文件:
@@ -106,8 +99,6 @@
- CSS 文件名也改为哈希命名
- 静态资源文件名同样使用哈希
-这一步不能阻止逆向,但能降低别人直接从 `dist/` 推断页面结构的便利性。
-
### 6. 生产包自动清理日志,并保留可切换开关
生产相关打包模式下,会自动清掉常见调试日志;同时保留一个方便排查 App 内问题的“保留日志”构建开关。
@@ -120,9 +111,9 @@
表现:
-- `production` 和 `production-atu` 下自动移除 `console.log`
-- `production` 和 `production-atu` 下自动移除 `console.debug`
-- `production` 和 `production-atu` 下自动移除 `console.info`
+- `production` 下自动移除 `console.log`
+- `production` 下自动移除 `console.debug`
+- `production` 下自动移除 `console.info`
- 生产相关模式下自动移除 `debugger`
- `console.warn` 和 `console.error` 保留,方便线上排查
- Jenkins 仍可继续使用原有默认打包命令
@@ -132,8 +123,6 @@
```bash
npm run build:prod
npm run build:prod:logs
-npm run build:atu-prod
-npm run build:atu-prod:logs
```
### 7. 部分高风险页面改为延迟挂载主内容 DOM
@@ -153,17 +142,9 @@ npm run build:atu-prod:logs
- 对依赖 `IntersectionObserver` 的页面,在 `await nextTick()` 之后再注册观察器
- 预加载结束逻辑仍然放在 `finally` 中,避免预加载失败时页面长期空白
-这一步的作用要明确:
-
-- 可以减少初始阶段 DOM 直接暴露的程度
-- 可以让“页面刚进来就看 Elements 面板抄结构”变得没那么直接
-- 不能阻止页面渲染完成后的继续抓取
-
-也就是说,它属于弱加固,而不是决定性的防扒手段。
-
### 8. 装饰背景堆图改为可选 canvas 渲染
-公共背景组件现在支持可选的 canvas 渲染模式,适合拿来处理活动页和榜单页那种“纯装饰背景层层堆图”的场景。
+公共背景组件现在支持可选的 canvas 渲染模式,适合处理活动页和榜单页那种“纯装饰背景层层堆图”的场景。
主要文件:
@@ -184,12 +165,10 @@ npm run build:atu-prod:logs
表现:
-- 多张纯装饰背景图会先合成到单个 canvas 中,而不是在 DOM 里直接挂一串 `
`
+- 多张纯装饰背景图会先合成到单个 canvas 中,而不是在 DOM 里直接挂一个个 `
`
- 从 Elements 面板直接看页面背景结构会比之前更不直观
- 受保护图片地址仍然继续走现有的运行时解析和缓存链路
-这一步不能阻止有经验的人继续拿到像素内容,但能明显降低“直接看 DOM 抄背景结构”的便利度。
-
### 9. 生产构建混淆再收紧,并补一轮明显语义类名收口
生产相关构建模式现在显式开启更严格的 `esbuild` 压缩参数,同时针对重点页面收了一轮最显眼的本地类名。
@@ -204,35 +183,17 @@ npm run build:atu-prod:logs
- [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` 是显式开关,不默认全局开启
-- 原因是 `BackgroundLayer` 是公共组件,默认全开会把所有背景层都切到 canvas 路径,带来额外的图片加载、重绘和兼容风险
-- 当前只在 `Activities / Ranking` 这类高风险页面显式传入 `:useCanvas=\"true\"`,把成本控制在需要加固的范围内
- [src/utils/protectedAssets.js](/D:/programs/likei-h5/src/utils/protectedAssets.js) 中的 `toCssBackgroundImage()` 用于把 `likei-protected:` 地址还原成 CSS 可用的 `background-image: url(...)`
-- 这个方法是兼容桥接,不是额外的加密层,主要服务于仍需使用内联背景图的场景
-
-如果后续需要在 `atu-prod` 分支做同类处理,建议优先对照这几个文件迁移:
-
-- [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)
-- [src/utils/protectedAssets.js](/D:/programs/likei-h5/src/utils/protectedAssets.js)
-- [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)
## 这套方案能挡住什么
@@ -247,20 +208,16 @@ npm run build:atu-prod:logs
## 当前边界
-这套改动仍然无法彻底防住以下情况:
+这套改动依然无法彻底防住以下情况:
- 通过 Network 面板或抓包获取图片请求
- 有经验的人持续分析前端运行时代码
- 自定义 WebView、自动化脚本、Hook 等方式截获资源
- 仅凭视觉观察后重新临摹布局和样式
-- 从一个本来就被允许渲染页面的客户端中提取 DOM、CSS、JS
-
-一个关键原则是:
+- 从本来就被允许渲染页面的客户端中提取 DOM、CSS、JS
只要客户端能把页面渲染出来,客户端就一定拿到了足够还原页面的信息。
-所以前端侧能做的,本质上只有“提高成本”,而不是“绝对防住”。
-
## 推荐测试方式
### 受保护页面拦截
@@ -308,17 +265,3 @@ npm run build
- 构建产物文件名中不再直观出现页面名
- 生产包中不再保留 `console.log`、`console.debug`、`console.info` 和 `debugger`
-## 后续仍可继续推进的方向
-
-如果继续坚持只改前端项目,可以优先考虑:
-
-- 把更敏感的装饰层、外框层继续往 `canvas` 渲染收口
-- 继续减少关键活动页中可直接阅读的结构语义
-- 继续替换剩余直接 `background-image` 或直出图片链路
-
-如果后续允许少量后端配合,优先级更高的是:
-
-- 敏感 OSS 目录改成私有读
-- 使用短时签名 URL
-- 给敏感图片做按用户生成的动态水印
-- 资源下发前校验 App 会话或设备身份
diff --git a/docs/security/frontend-hardening.zh-CN.updates.md b/docs/security/frontend-hardening.zh-CN.updates.md
index a99fd9c..0486c9c 100644
--- a/docs/security/frontend-hardening.zh-CN.updates.md
+++ b/docs/security/frontend-hardening.zh-CN.updates.md
@@ -7,29 +7,28 @@
- 生产构建混淆进一步收紧,`esbuild` 在生产相关模式下显式开启了更强的标识符、语法和空白压缩,并去除了合法注释输出。相关文件在 [vite.config.js](/D:/programs/likei-h5/vite.config.js)。
- 公共背景组件 [BackgroundLayer.vue](/D:/programs/likei-h5/src/components/BackgroundLayer.vue) 新增了 `useCanvas` 模式,装饰性多层背景会优先绘制到单个 canvas,而不是在 DOM 中直接暴露多张 `
`。
- `canvas` 背景已扩展到更多高风险页面:
- [LesserBairam/index.vue](/D:/programs/likei-h5/src/views/Activities/LesserBairam/index.vue),
- [LoginReward/index.vue](/D:/programs/likei-h5/src/views/Activities/LoginReward/index.vue),
- [LuckyDollars/Season3/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season3/index.vue),
- [LuckyDollars/Season4/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season4/index.vue),
- [SpringFestival/index.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/index.vue),
- [Ranking/Couple/index.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/index.vue),
- [Ranking/GamesKing/index.vue](/D:/programs/likei-h5/src/views/Ranking/GamesKing/index.vue),
- [Ranking/KingAndQueen/TopList.vue](/D:/programs/likei-h5/src/views/Ranking/KingAndQueen/TopList.vue),
- [Ranking/Overall/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Overall/Ranking.vue),
+ [LesserBairam/index.vue](/D:/programs/likei-h5/src/views/Activities/LesserBairam/index.vue)、
+ [LoginReward/index.vue](/D:/programs/likei-h5/src/views/Activities/LoginReward/index.vue)、
+ [LuckyDollars/Season3/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season3/index.vue)、
+ [LuckyDollars/Season4/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season4/index.vue)、
+ [SpringFestival/index.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/index.vue)、
+ [Ranking/Couple/index.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/index.vue)、
+ [Ranking/GamesKing/index.vue](/D:/programs/likei-h5/src/views/Ranking/GamesKing/index.vue)、
+ [Ranking/KingAndQueen/TopList.vue](/D:/programs/likei-h5/src/views/Ranking/KingAndQueen/TopList.vue)、
+ [Ranking/Overall/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Overall/Ranking.vue)、
[Ranking/WeeklyStar/WeeklyStar.vue](/D:/programs/likei-h5/src/views/Ranking/WeeklyStar/WeeklyStar.vue)。
-- 第二轮语义类名收口已继续推进,当前已覆盖:
- [Ranking/Couple/index.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/index.vue),
- [LuckyDollars/Season4/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season4/index.vue),
- [SpringFestival/index.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/index.vue),
- [SpringFestival/Ranking.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/Ranking.vue),
- [Ranking/Overall/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Overall/Ranking.vue),
+- 第二轮语义类名收口已经继续推进,当前已覆盖:
+ [Ranking/Couple/index.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/index.vue)、
+ [LuckyDollars/Season4/index.vue](/D:/programs/likei-h5/src/views/Activities/LuckyDollars/Season4/index.vue)、
+ [SpringFestival/index.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/index.vue)、
+ [SpringFestival/Ranking.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/Ranking.vue)、
+ [Ranking/Overall/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Overall/Ranking.vue)、
[Ranking/WeeklyStar/WeeklyStar.vue](/D:/programs/likei-h5/src/views/Ranking/WeeklyStar/WeeklyStar.vue)。
- [SpringFestival/Ranking.vue](/D:/programs/likei-h5/src/views/Activities/SpringFestival/Ranking.vue) 已额外做了时序加固:
- 组件会在 `nextTick()` 之后再注册 `IntersectionObserver`,并在 `onUnmounted` 时执行 `disconnect()`,避免监听节点还没稳定挂载时就注册,或页面切换后残留观察器。
-- [Ranking/Couple/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/Ranking.vue) 已清理上一轮遗留的乱码注释,并统一替换为中文注释,方便后续排查与跨分支迁移。
-- [BackgroundLayer.vue](/D:/programs/likei-h5/src/components/BackgroundLayer.vue) 的 `useCanvas` 继续保持显式开启,而没有改成默认值 `true`:
- 这是为了避免把所有背景层都切到 canvas 渲染路径,给普通页面增加不必要的加载、绘制和重绘成本。
-- [protectedAssets.js](/D:/programs/likei-h5/src/utils/protectedAssets.js) 中的 `toCssBackgroundImage()` 作用也已明确:
+ 组件会在 `nextTick()` 之后再注册 `IntersectionObserver`,并在 `onUnmounted` 时执行 `disconnect()`。
+- [Ranking/Couple/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/Ranking.vue) 已清理上一轮遗留的乱码注释,并统一替换为中文注释。
+- [BackgroundLayer.vue](/D:/programs/likei-h5/src/components/BackgroundLayer.vue) 的 `useCanvas` 继续保持显式开启,而没有改成默认值 `true`。
+- [protectedAssets.js](/D:/programs/likei-h5/src/utils/protectedAssets.js) 中的 `toCssBackgroundImage()` 作用已明确:
它负责把 `likei-protected:` 地址还原为 CSS 可直接使用的 `url(...)` 字符串,主要用于必须保留 `background-image` 的内联样式场景。
## 当前边界
@@ -42,17 +41,4 @@
- 使用 `npm run build` 验证生产包可正常构建。
- 使用 `npm run dev:prod` 或 `npm run preview` 验证活动页、榜单页在生产态逻辑下仍能正常显示。
-- 重点检查 `SpringFestival`、`Season4`、`WeeklyStar`、`Overall` 这几类近期改动较多的页面。
-
-## `atu-prod` 迁移建议
-
-- 如果后续要在 `atu-prod` 分支复用同类处理,优先迁移本轮涉及的三个核心文件:
- [Ranking/Couple/Ranking.vue](/D:/programs/likei-h5/src/views/Ranking/Couple/Ranking.vue)、
- [BackgroundLayer.vue](/D:/programs/likei-h5/src/components/BackgroundLayer.vue)、
- [protectedAssets.js](/D:/programs/likei-h5/src/utils/protectedAssets.js)。
-- 同步迁移文档文件,避免分支间的实现与说明脱节:
- [frontend-hardening.zh-CN.md](/D:/programs/likei-h5/docs/security/frontend-hardening.zh-CN.md)、
- [frontend-hardening.zh-CN.updates.md](/D:/programs/likei-h5/docs/security/frontend-hardening.zh-CN.updates.md)。
-- 后续如果主分支继续更新了这些文档,切到目标分支后可直接执行:
- `npm run docs:sync:security -- master`
-- 该命令依赖脚本 [scripts/sync-security-docs.js](/D:/programs/likei-h5/scripts/sync-security-docs.js),前提是主分支里的文档版本已经提交到 Git。
+- 重点检查 `SpringFestival`、`Season4`、`WeeklyStar`、`Overall` 这些近期改动较多的页面。
diff --git a/src/App.vue b/src/App.vue
index e99f3ab..5069c58 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,47 +1,24 @@
-
- {{ watermarkText }}
-
@@ -82,31 +59,4 @@ body {
-webkit-touch-callout: none;
user-select: none;
}
-
-.security-watermark {
- position: fixed;
- inset: 0;
- z-index: 9999;
- pointer-events: none;
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 48px 24px;
- padding: 40px 16px;
- opacity: 0.11;
- overflow: hidden;
-}
-
-.security-watermark span {
- display: flex;
- align-items: center;
- justify-content: center;
- min-height: 96px;
- color: #0f172a;
- font-size: 14px;
- font-weight: 700;
- letter-spacing: 1px;
- text-transform: uppercase;
- transform: rotate(-24deg);
- white-space: nowrap;
-}