关键在于用 proxy 精准代理敏感配置对象(如 __pay_config__),先 freeze 再拦截 get/set,微任务末尾快照比对并还原非法变更,还原时绕过 proxy 避免循环,辅以 mutationobserver 监控 dom 反射。
关键在于不依赖“锁死”对象,而是用 proxy 拦截属性访问与赋值,在微任务执行前完成校验与还原。
只代理需保护的配置对象,而非整个全局环境
不要对 window 或 globalThis 做全量代理——开销大、易误伤、触发兼容性问题。应精准定位被第三方业务频繁修改的配置对象(如 __PAY_CONFIG__、SDK_OPTS),仅对其做 Proxy 包装:
- 用
Object.freeze()预先冻结原始配置结构(防新增/删属性) - 再用
Proxy拦截set和get,重点防御display、enabled、callbackUrl等敏感字段 - 避免递归代理嵌套对象,除非明确需要深防护;可采用“懒代理”策略:仅当访问到某子属性时才代理该层级
在微任务队列清空前主动拦截并快照比对
第三方脚本常通过 Promise.then、MutationObserver 回调或 queueMicrotask 修改配置。可在每次微任务开始前插入校验钩子:
- 用
queueMicrotask(() => { /* 校验逻辑 */ })在当前微任务末尾注入检查点 - 对比当前值与初始化快照(建议用
JSON.stringify+Object.getOwnPropertyDescriptors组合判断是否被篡改) - 若发现非法变更(如
enabled: false被设为true),立即还原并记录 warn 日志,不抛错以免阻断正常流程
修复时不触发新微任务,避免监听循环
还原操作本身若引发 setter 或触发响应式更新,可能再次进入微任务队列,造成无限循环。必须切断这个链路:
- 还原时临时移除
Proxy,用Object.defineProperty直接写入原始对象(绕过拦截) - 或使用
Reflect.set(target, key, value, receiver)并传入原始 target,确保不走 proxy 的 set trap - 还原后重新挂载 Proxy,但跳过首次初始化校验(加 flag 控制)
配合 MutationObserver 监控 DOM 中的配置反射行为
部分第三方组件会把配置映射到 DOM 属性(如 <div data-pay-config>),再从 DOM 读取。这类“间接篡改”需额外兜底:<ul>
<li>监听目标容器的 <code>attributes 变更,过滤 data- 前缀属性
attributeFilter: ['data-pay-config'],避免监听泛滥










