267 lines
11 KiB
Markdown
267 lines
11 KiB
Markdown
# Frontend Hardening Notes
|
|
|
|
## Purpose
|
|
|
|
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 stay within the frontend project.
|
|
|
|
They do not rely on:
|
|
|
|
- backend API changes
|
|
- private OSS buckets
|
|
- signed image URLs
|
|
- server-side image rewriting
|
|
|
|
## What Was Added
|
|
|
|
### 1. Protected page access control
|
|
|
|
Protected routes are blocked outside the official app environment in production-like modes.
|
|
|
|
Main files:
|
|
|
|
- [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)
|
|
|
|
Behavior:
|
|
|
|
- public routes still open normally
|
|
- protected routes redirect to `/#/not_app` outside the app
|
|
- protected API requests are rejected when the app bridge is unavailable
|
|
|
|
### 2. Runtime anti-debug and anti-copy restrictions
|
|
|
|
Protected pages add a lightweight runtime restriction layer in production-like modes.
|
|
|
|
Main files:
|
|
|
|
- [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)
|
|
|
|
Behavior:
|
|
|
|
- blocks common devtools shortcuts
|
|
- blocks right-click, drag, copy, and text selection on protected pages
|
|
- reduces long-press image save convenience
|
|
|
|
### 3. Protected asset URL layer for `Activities` and `Ranking`
|
|
|
|
Most `Activities/` and `Ranking/` image references no longer expose raw OSS URLs directly in templates.
|
|
|
|
Main files:
|
|
|
|
- [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)
|
|
|
|
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
|
|
- pages that missed `v-smart-img` still get a runtime fallback for protected image `src`
|
|
|
|
### 4. `background-image` compatibility fixes
|
|
|
|
Several high-risk pages previously exposed asset URLs through inline `background-image: url(...)`.
|
|
|
|
Adjusted files:
|
|
|
|
- [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)
|
|
|
|
Behavior:
|
|
|
|
- protected helpers are used before writing image values into CSS
|
|
- fewer raw asset URLs appear directly in template or style strings
|
|
|
|
### 5. Build artifact readability reduction
|
|
|
|
Build output names were changed from readable page/component names to hash-based filenames.
|
|
|
|
Main file:
|
|
|
|
- [vite.config.js](/D:/programs/likei-h5/vite.config.js)
|
|
|
|
Behavior:
|
|
|
|
- JS chunk names no longer reveal page names such as `TopList`, `WeeklyStar`, or `Ranking`
|
|
- CSS files also use hash-based names
|
|
- static asset filenames are hash-based
|
|
|
|
### 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.
|
|
|
|
Main files:
|
|
|
|
- [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)
|
|
|
|
Behavior:
|
|
|
|
- `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
|
|
|
|
Useful commands:
|
|
|
|
```bash
|
|
npm run build:prod
|
|
npm run build:prod:logs
|
|
```
|
|
|
|
### 7. Deferred main DOM mounting for selected high-risk pages
|
|
|
|
Some activity and ranking pages previously used `v-show="!isLoading"` for the main content. That kept the full DOM tree mounted early, which made initial inspection easier and also caused some observer timing issues.
|
|
|
|
These pages were updated to mount their main content with `v-if="!isLoading"` instead:
|
|
|
|
- [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)
|
|
|
|
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
|
|
|
|
### 8. Canvas-rendered decorative background stacks
|
|
|
|
The shared background layer component supports a canvas rendering mode for stacked background images.
|
|
|
|
Main file:
|
|
|
|
- [src/components/BackgroundLayer.vue](/D:/programs/likei-h5/src/components/BackgroundLayer.vue)
|
|
|
|
Current high-risk pages using this mode:
|
|
|
|
- [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)
|
|
|
|
Behavior:
|
|
|
|
- stacked decorative backgrounds are drawn into a single canvas instead of a readable `<img>` list
|
|
- most page-level decorative background structure becomes less obvious in Elements inspection
|
|
- protected asset resolution still goes through the existing runtime/cache pipeline
|
|
|
|
### 9. Stronger production minification and selector cleanup
|
|
|
|
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:
|
|
|
|
- [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` 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:
|
|
|
|
- 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
|
|
|
|
This frontend-only hardening is helpful against:
|
|
|
|
- direct browser opening of protected routes
|
|
- low-effort DOM scraping
|
|
- copying image URLs from templates or page source
|
|
- reading obvious page intent from build artifact names
|
|
- simple right-click, drag-save, long-press, and casual copying
|
|
- basic page reconstruction that depends on immediately available DOM structure
|
|
|
|
## Current Limits
|
|
|
|
These changes still do not fully prevent:
|
|
|
|
- network-level image capture
|
|
- devtools users with enough time and persistence
|
|
- custom WebView, automation, or hook-based extraction
|
|
- rebuilding the same layout after visual inspection
|
|
- extracting DOM, CSS, and JS from any client that is allowed to render the page
|
|
|
|
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
|
|
|
|
### Protected route blocking
|
|
|
|
Use:
|
|
|
|
```bash
|
|
npm run dev:prod
|
|
```
|
|
|
|
or:
|
|
|
|
```bash
|
|
npm run build
|
|
npm run preview
|
|
```
|
|
|
|
### Asset and page rendering checks
|
|
|
|
In production-like mode, verify:
|
|
|
|
- `Activities` and `Ranking` pages still render correctly
|
|
- protected page images still display normally
|
|
- protected asset URLs are less visible in runtime DOM and build output
|
|
- pages switched from `v-show` to `v-if` still render after preload completes
|
|
- pages with load-more observers still trigger lazy loading correctly
|
|
|
|
### Build output checks
|
|
|
|
Run:
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
Expected:
|
|
|
|
- `dist/js` filenames are hash-based
|
|
- `dist/css` filenames are hash-based
|
|
- no obvious page names appear in bundle filenames
|
|
- production bundles no longer retain `console.log`, `console.debug`, `console.info`, or `debugger`
|
|
|