object.seal仅限制对象自身属性的增删改,不阻止变量重赋值;需结合const声明、递归seal嵌套对象及defineproperty加固关键字段实现三层防护。

Object.seal 本身不能防止“对象被覆盖”,它只控制对象**自身属性的增删改配置**,不阻止变量重新赋值。所谓“核心加密微任务配置被作为普通对象覆盖”,本质是引用被替换(如 config = {...}),而非对象内部被篡改——这是作用域和赋值机制问题,不是密封能解决的。
明确边界:seal 管不了变量赋值,只管对象内部
假设你有:
const cryptoConfig = { keyLength: 256, mode: 'AES-GCM' };
Object.seal(cryptoConfig);
✅ 安全行为:
-
cryptoConfig.mode = 'AES-CBC';—— 允许(只要 writable) -
delete cryptoConfig.keyLength;—— 失败(返回 false) -
cryptoConfig.newField = true;—— 静默无效(非严格模式)或报错(严格模式)
❌ seal 完全无法防御的行为:
-
cryptoConfig = { keyLength: 128 };—— 直接报错(因为 const 声明不可重赋值) -
let config = cryptoConfig; config = {};—— 无影响,原对象仍 sealed -
import { cryptoConfig } from './config.js'; cryptoConfig = {};—— 模块导出绑定不可重赋值(ESM 下报错)
真正防覆盖的三层组合策略
要让配置既“结构稳定”又“引用不可替换”,需分层设防:
-
顶层冻结声明:用
const声明配置变量,配合 ESM 模块默认导出,天然禁止外部重赋值 -
对象结构密封:调用
Object.seal()锁定自有属性(不可增、不可删、不可重配置),保留运行时可更新字段(如临时 token、动态 salt) -
嵌套对象手动密封:若配置含子对象(如
{ crypto: { iv: new Uint8Array(12) } }),需递归调用Object.seal()或使用Object.freeze()控制深层
典型安全初始化写法
推荐这样定义核心配置:
// config/crypto.js
export const cryptoConfig = Object.seal({
keyLength: 256,
mode: 'AES-GCM',
ivLength: 12,
// 嵌套对象需单独 seal(若需修改其字段)
defaults: Object.seal({
padding: 'pkcs7',
authTagLength: 16
})
});
// 外部使用(安全)
import { cryptoConfig } from './config/crypto.js';
cryptoConfig.mode = 'AES-CCM'; // ✅ 允许
cryptoConfig.defaults.padding = 'none'; // ✅ 允许(defaults 自身也被 seal)
cryptoConfig.newKey = 'xxx'; // ❌ 静默失败
delete cryptoConfig.ivLength; // ❌ 失败
额外加固建议
仅靠 seal 不足以应对高安全场景,可叠加:
- 用
Object.defineProperty显式设writable: false关键字段(如keyLength),再 seal,确保值也不可变 - 搭配
Object.isSealed()在关键入口校验,防止意外未 seal 的配置流入 - 构建时通过 TypeScript 类型 +
readonly修饰符提前拦截误操作(编译期防护)










