可通过Object.getOwnPropertyDescriptor检测原生API属性是否被篡改,并结合Object.defineProperty或冻结策略恢复/锁定关键属性,识别和防御对XMLHttpRequest、fetch等的劫持。

可以通过 Object.getOwnPropertyDescriptor 检测原生 API 属性是否被篡改,并结合 Object.defineProperty 或冻结策略恢复/锁定关键属性,从而识别和防御恶意脚本对 XMLHttpRequest、fetch、console、addEventListener 等的劫持。
识别被篡改的关键原生 API
恶意脚本常通过重写原型方法(如 XMLHttpRequest.prototype.open)或覆盖全局对象属性(如 window.fetch)实现监听或拦截。使用 getOwnPropertyDescriptor 可获取属性的原始定义,判断其是否被替换:
- 检查
value是否为原生函数(toString()返回[native code]) - 确认
writable、configurable是否仍为true(被劫持后常被设为false或篡改) - 比对
get/set描述符是否存在非原生逻辑
例如:
const desc = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'open');
if (desc && desc.value && desc.value.toString().indexOf('[native code]') === -1) {
console.warn('XMLHttpRequest.prototype.open 已被劫持');
}
主动恢复并锁定核心属性
检测到异常后,不能仅依赖重新赋值(可能被再次覆盖),而应利用原生构造器重建并锁定:
- 从 iframe 或
eval('this')等隔离上下文中提取未污染的原生函数 - 用
Object.defineProperty强制还原value,并设writable: false和configurable: false - 对整个对象(如
console)可使用Object.freeze()防止新增/删除属性
示例(安全恢复 fetch):
const safeFetch = window.__originalFetch || fetch;
Object.defineProperty(window, 'fetch', {
value: safeFetch,
writable: false,
configurable: false,
enumerable: true
});
在页面早期注入防御逻辑
防御必须早于第三方脚本执行,否则劫持已发生:
- 将检测代码放在
<head>内首个<script>,且使用defer或内联(避免异步加载延迟) - 借助
document.write(谨慎)或动态创建script标签并插入到head最前 - 对 Service Worker 或模块环境,可在
import前通过self或globalThis执行校验
补充:监控与告警机制
静态防护之外,可建立轻量级运行时监控:
- 定时轮询关键属性描述符变化(如每 500ms 检查一次
addEventListener) - 利用
Proxy包裹window或XMLHttpRequest.prototype(注意兼容性,仅现代浏览器) - 发现篡改时记录堆栈(
new Error().stack)、上报日志,甚至触发页面重载或禁用可疑脚本

















