From f7df4558af665e6917d5f74b5b4a22f0ad52b496 Mon Sep 17 00:00:00 2001 From: essence-of-the-soul Date: Wed, 5 Aug 2026 11:53:54 +0000 Subject: [PATCH] =?UTF-8?q?fix(IK49NV):=20=E7=A7=BB=E9=99=A4=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E7=A1=AC=E7=BC=96=E7=A0=81=E5=BC=B1=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E5=AF=86=E9=92=A5=EF=BC=8C=E6=94=B9=E4=B8=BA=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E6=B3=A8=E5=85=A5=E5=B9=B6=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit global.ts 原硬编码 ENCRYPTION_KEY = 'ocmanager',暴露在浏览器源码 中,任何用户均可查看,AES 加密形同虚设。 修复: - 移除硬编码常量,改为 getEncryptionKey() 函数从 Vite 环境变量 VITE_ENCRYPTION_KEY 读取密钥 - 新增强度校验:密钥长度不少于 16 字符,且不得为已知弱值 (ocmanager/secret/key 等),校验失败抛异常(fail-fast) - encryptIfPlainWithKey 不再接受调用方传入密钥参数,统一使用 getEncryptionKey() 获取受控密钥,避免传入弱值 - 补充 CryptoJS 导入(原函数引用但未导入) - .env.development/.env.site 添加 VITE_ENCRYPTION_KEY 占位与说明, 生产环境须替换为高强度随机值 关联 issue IK49NV --- manager/frontend/.env.development | 5 ++++ manager/frontend/.env.site | 3 +++ manager/frontend/src/config/global.ts | 34 ++++++++++++++++++++++++++- manager/frontend/src/utils/func.ts | 11 ++++++++- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/manager/frontend/.env.development b/manager/frontend/.env.development index 5698c2b..2318238 100755 --- a/manager/frontend/.env.development +++ b/manager/frontend/.env.development @@ -1,2 +1,7 @@ # 开发环境 VITE_BASE_URL = / + +# IK49NV: 前端 AES 加密密钥,必须通过环境变量注入,不得硬编码在源码中。 +# 开发环境使用此占位密钥;生产环境务必在 .env.production 中替换为 +# 高强度随机字符串(建议 32+ 字符),且不得提交到版本控制。 +VITE_ENCRYPTION_KEY = dev-only-do-not-use-in-prod-32chars diff --git a/manager/frontend/.env.site b/manager/frontend/.env.site index 37c0b57..f1f482d 100755 --- a/manager/frontend/.env.site +++ b/manager/frontend/.env.site @@ -1,2 +1,5 @@ # 仅用于将构建产物部署到自定义子路径(带子路径的反向代理场景) VITE_BASE_URL = / + +# IK49NV: 前端 AES 加密密钥,部署时务必通过环境变量覆盖为高强度随机值。 +VITE_ENCRYPTION_KEY = dev-only-do-not-use-in-prod-32chars diff --git a/manager/frontend/src/config/global.ts b/manager/frontend/src/config/global.ts index 671374d..1d9c467 100755 --- a/manager/frontend/src/config/global.ts +++ b/manager/frontend/src/config/global.ts @@ -498,4 +498,36 @@ export const GLOBAL_TERMS = { // Agent管理 AGENT_MANGE: 'Agent管理', }; -export const ENCRYPTION_KEY = 'ocmanager'; +/** + * IK49NV: 前端 AES 加密密钥原硬编码为 'ocmanager',暴露在浏览器源码中, + * 任何用户均可查看,加密形同虚设。 + * + * 修复:密钥改为通过 Vite 构建时环境变量 VITE_ENCRYPTION_KEY 注入, + * 不再硬编码在源码中。同时增加强度校验:密钥长度不少于 16 字符, + * 且不得为已知的弱值。校验失败时抛出异常(fail-fast),避免静默 + * 使用弱密钥。 + * + * 部署方应在 .env.production(或对应环境文件)中设置 + * VITE_ENCRYPTION_KEY 为一个高强度随机字符串(建议 32+ 字符)。 + */ +const WEAK_KNOWN_KEYS = new Set(['ocmanager', '', 'secret', 'key', 'password', 'aes-key']); + +let _cachedEncryptionKey: string | null = null; + +export function getEncryptionKey(): string { + if (_cachedEncryptionKey !== null) return _cachedEncryptionKey; + + const key = (import.meta.env.VITE_ENCRYPTION_KEY as string | undefined) ?? ''; + + if (key.length < 16) { + throw new Error( + 'ENCRYPTION_KEY 未配置或长度不足 16 字符,请在环境变量 VITE_ENCRYPTION_KEY 中设置高强度密钥', + ); + } + if (WEAK_KNOWN_KEYS.has(key.toLowerCase())) { + throw new Error('ENCRYPTION_KEY 配置为已知弱值,请更换为高强度随机密钥'); + } + + _cachedEncryptionKey = key; + return key; +} diff --git a/manager/frontend/src/utils/func.ts b/manager/frontend/src/utils/func.ts index 4fa0ae5..921ed3b 100755 --- a/manager/frontend/src/utils/func.ts +++ b/manager/frontend/src/utils/func.ts @@ -1,5 +1,7 @@ import dayjs from 'dayjs'; +import CryptoJS from 'crypto-js'; import router from '@/router/index'; +import { getEncryptionKey } from '@/config/global'; // 前端添加id标识 export function formatList(list: any[], key: string, set_key: string) { @@ -158,9 +160,16 @@ export function toPasswordBase64(u8) { return btoa(binary); } -export async function encryptIfPlainWithKey(plain, keyStr) { +/** + * 使用受控 AES 密钥加密明文(若已加密则原样返回)。 + * + * IK49NV: 密钥不再由调用方传入(避免传入硬编码弱密钥 'ocmanager'), + * 改为统一从 getEncryptionKey() 获取经环境变量注入且校验通过的密钥。 + */ +export async function encryptIfPlainWithKey(plain: string): Promise { if (!plain || plain.startsWith('enc:')) return plain; try { + const keyStr = getEncryptionKey(); const encrypted = CryptoJS.AES.encrypt(plain, keyStr).toString(); return `enc:${encrypted}`; } catch (fallbackError) { -- Gitee