简而言之:EEEEEEEK!不要这样做!相反,决定什么需要被保护,并保护那个。不惜一切代价避免轮询(定期检查)。尤其要避免对任何东西进行定期的繁重检查。
并非所有更改都可以跟踪。大多数变化都很难跟踪,因为有很多事情可以改变。
可以检测到 DOM 的更改(新节点、删除的节点、更改的属性)。另一个答案建议定期检查innerHTML,但最好使用mutation observers(Firefox、Chrome 支持)或较旧的突变事件(DOMSubtreeModified 等)(支持因事件而异)。
无法可靠地检测到对标准方法的更改,除非通过手动比较每个方法和属性 (eeeek)。这包括需要引用大量对象,例如 Array.prototype.splice(当然还有 Array 和 Array.prototype),并定期运行 heavy 脚本。但是,这不是用户脚本通常会做的事情。
输入的状态是一个属性,而不是一个属性。这意味着文档 HTML 不会改变。如果状态由脚本更改,change 事件也不会触发。同样,唯一的解决方案是手动轮询 每个输入 (eeek)。
没有可靠的方法来检测是否附加了事件处理程序。对于初学者,您需要保护 onX 属性(第 2 段),检测对 addEventListener (ek) 的任何调用(不触发第 2 段检查),检测您的库对相应方法的任何调用( jQuery.bind 和其他几个)。
有一个对你有利,并且可能是唯一一个:用户脚本在页面加载时运行(永远不会更快),所以你有足够的时间来准备你的防御。 not even that plays in your favor(感谢 Brock Adams 的注意和链接)
您可以通过将其替换为您自己的 (ek) 来检测已调用的标准方法。您需要以这种方式(eek)检测许多方法,一些通过浏览器,一些通过您的框架。事实上,IE(甚至可以指示 firefox,感谢@Brock)不会让您接触 DOM 类的原型,这会在“eek”中添加另一个“e”或两个。某些方法只能通过方法调用(返回值,回调参数)获得的事实增加了另一个“e”或两个,总共“eeeek”。爬过整个window 的想法将被安全异常和无法捕获的安全异常所挫败。也就是说,除非您不使用 iFrame 并且您不在 iFrame 中。
即使您检测到每个方法调用,也可以通过写入innerHTML 来更改 DOM。 Firefox 和 Chrome 支持 Mutation Observers,因此您可以使用它们。
即使您检测到对预先存在的方法的每个方法调用并监听突变,大多数属性都不会被两者反映,因此您还需要观察每个对象的所有属性。祈祷某人不要使用您永远猜不到的键添加不可枚举的属性。顺便说一句,这也会捕获 DOM 突变。在 ES6 中,可以观察对象的属性集。我不确定您是否可以将设置器附加到 ES5 中的现有对象属性(同时遵守 ES3 语法)。轮询每个属性是 eeeek。
当然,您应该允许您自己的 脚本进行一些更改。工作流程是设置一个标志(不能从全局范围访问!)“我是合法的”,做你的工作,并清除标志 - 记住也要在你的所有回调的两侧。然后方法观察者将检查标志是否设置。属性看门狗将更难检测更改是否有效,但可以从脚本通知每个合法更改(手动;再次确保用户脚本看不到该通知流)。哎呀。
一开始我没有意识到一个完全不同的问题:用户脚本在页面加载时运行,但它们也可以创建 iFrame。用户脚本会:1) 检测到您的脚本拦截器,2) 将页面从轨道中删除(您无法阻止 document.body.innerHTML =,至少不会没有严重篡改document.body),3)插入一个带有原始URL的iframe(防止双重加载服务器端?)和4)有足够的时间在你的保护被加载之前对那个空的iframe采取行动。
另外,请参阅the duplicate found by Brock Adams,其中显示了我认为不应该进行的其他几项检查。