deleteproperty 是 proxy 中唯一拦截 delete 操作的陷阱,需显式定义并配合白名单(如 set)、不可配置属性检查、symbol 键处理及 has/get 协同防御,否则关键字段将暴露。

deleteProperty 是 Proxy 中唯一能拦截 delete obj.key 操作的陷阱函数,但它不会自动生效——必须显式定义在 handler 里,并配合合理的判断逻辑,才能真正守住核心配置字段。
确认 deleteProperty 是否被正确定义
很多问题其实出在“根本没写这个陷阱”。Proxy 不会默认拦截 delete,只有 handler 对象里明确写了 deleteProperty(target, key) 方法,删除操作才会进到你的控制逻辑里。
- 没定义 → 删除直接作用于原对象,id、status、version 这类关键字段毫无防护
- 有定义但没 return → 行为等同于没写(JavaScript 默认返回 undefined,被视为 false,导致删除失败但无提示)
- 写了但只 return true → 所有删除都“成功”,等于放行,起不到保护作用
用白名单精准拦截业务关键字段
靠字符串匹配(比如 key.includes('id'))容易误伤 tempId、cacheId、backupId 等非核心字段。更可靠的方式是维护一个静态白名单:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 用
Set存储受保护字段名:const protected = new Set(['id', 'status', 'createdAt', 'version']) - 在 deleteProperty 中直接查:
if (protected.has(key)) { return false; } - 对非白名单字段,再调用
Reflect.deleteProperty(target, key)委托原行为
处理不可配置属性和 Symbol 键
如果字段是用 Object.defineProperty(obj, 'locked', { configurable: false }) 定义的,delete 操作根本不会触发 deleteProperty —— 它会直接失败(严格模式抛错,非严格模式静默)。所以得提前兜底:
- 在 deleteProperty 开头用
Object.getOwnPropertyDescriptor(target, key)检查是否可配置 - 对不可配置属性,直接返回 false 或 throw Error,避免逻辑遗漏
- 别忘了 Symbol 类型的 key:
typeof key === 'symbol'要单独判断,防止 Symbol('locked') 这类敏感标识被绕过
配合 has 和 get 做纵深防御
单靠拦截删除不够。攻击者可能先用 'id' in proxy 判断存在性,再决定是否操作;或通过读取触发副作用。建议同步加固:
- 在
has陷阱中对 protected 字段始终返回 true,防止业务代码因误判“不存在”而跳过校验 - 在
get陷阱中对敏感字段加访问日志,或结合权限上下文做简单检查 - 所有拦截逻辑里优先使用
Reflect.*()方法,保持与原生语义一致,减少边界异常










