原型链污染是JavaScript中因不安全对象合并或属性赋值导致的高危漏洞,攻击者通过构造__proto__等特殊键名篡改Object.prototype,使所有对象继承恶意属性;防御需组合输入过滤、Object.create(null)、升级安全库版本、运行时冻结原型及服务端强制鉴权。
无法真正“禁止”控制台篡改原型链,但可以大幅提高攻击门槛、及时发现异常,并确保权限逻辑不被绕过——关键在于不把权限判断放在前端执行,而把校验和决策权牢牢锁在服务端。
前端不存权限判定逻辑
用户角色、菜单可见性、按钮是否禁用等,看似是前端控制,实则只是服务端返回的渲染结果。任何在 JavaScript 中写死的 if (user.role === 'admin') 或 hasPermission('delete') 都可能被控制台直接覆盖或跳过。
正确做法:
- 登录后由后端一次性下发精简、不可变的权限声明(如 JWT payload 中的 scopes 数组或 RBAC 角色码)
- 前端仅做“状态映射”,例如根据 scopes.includes('order:delete') 显示/隐藏按钮,但不依赖它决定是否发起请求
- 所有敏感操作(如删除订单、导出数据)必须携带完整上下文(如资源 ID、操作类型)向后端发起独立鉴权请求
防御原型链污染本身
攻击者常通过控制台执行 Object.prototype.isAdmin = true 或注入 {"__proto__": {"isAdmin": true}} 来污染全局对象,进而干扰前端权限判断。防御需多层拦截:
- 解析用户输入(URL 参数、JSON 字符串、表单数据)前,使用白名单键名过滤器,主动剔除 __proto__、constructor、prototype 及其嵌套路径(如 a.__proto__.b)
- 避免使用 lodash.merge、deepAssign 等不安全合并函数处理用户数据;改用 structuredClone()(现代浏览器)或 JSON.parse(JSON.stringify())(兼容场景)进行浅净化
- 对核心权限工具对象(如 PermissionService 实例)调用 Object.freeze(),防止运行时属性被动态添加
服务端强制二次鉴权
前端一切“权限开关”都只是装饰。真正的防线永远在后端:
- 每个敏感接口必须校验:当前用户身份 + 请求中的资源 ID + 操作意图,三者缺一不可
- 不要只查角色,要查“该用户对这个具体订单是否有删除权”——例如检查订单所属人是否为当前用户,或是否存在跨部门审批流
- 对高频操作(如批量导出、删除)启用临时令牌或滑动窗口限流,异常行为(如 1 秒内连发 50 次删除)立即触发风控拦截
运行时监控与告警
即使做了上述防护,也建议加入轻量级检测机制,用于发现可疑调试行为:
- 定时检测 Object.prototype 是否被新增非原生属性(如遍历 keys 后排除已知方法)
- 监听 console.error 或未捕获异常,若出现大量 Permission denied 类日志但无对应请求,可能是脚本被篡改后静默失败
- 将检测结果以低优先级上报(不阻断功能),供安全团队分析趋势,而非弹窗警告用户(易被绕过)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











