JavaScript(或浏览器扩展)如何检测受限函数的使用?

4
我正在开发一个脚本扩展,类似于Greasemonkey或Chrome的内容脚本引擎。这个扩展将允许脚本编写者做非常危险的事情,比如访问本地文件。
如果我将该扩展发布给公众,我希望它能够警告初学者,如果一个脚本将使用“危险”的功能。我希望这个警告尽可能难以绕过。
例如,该扩展可以搜索受保护的字符串GM_openSQL_Connection,并警告用户--可能像这样:
Bad script warning 假设由于沙箱机制,基础网页永远无法访问GM_openSQL_Connection。同样,任何script节点也无法访问。
但是,脚本编写者仍然可以绕过上述简单搜索,例如:
eval (decodeURI ("GM_op%65nSQL_Connection (...);") )

所以问题是,恶意脚本编写者可以用哪些方法欺骗受限函数使用检查,我该如何防范这种恶作剧?
注意:虚假警告可能是可以接受的。例如,如果脚本作者在静态字符串中使用文本“GM_openSQL_Connection”,那么他只需要忍受(虚假的)警告。

2
完全无关,但我喜欢你的示例警告。 :) - seeming.amusing
你不能仅仅因为函数名就说它是危险的。只有行为才能被列入黑名单,而非名称。那些直接访问Cookie和远程访问第三方主机的函数通常被认为是最危险的(这并不意味着它们一定是危险的,但这可能是一个警告)。其他一些模式也可能被视为不受欢迎。 - YuS
我建议使用与JavaScript Deobfuscator相同的方法(使用调试接口获取所有函数调用,无论它们如何编译),但这并没有帮助。考虑var foo = window["GM_op" + "enSQL_Connection"];foo(...)。您不能仅依靠函数名称,因为函数名称可以轻松更改。 - Wladimir Palant
@Yuri,我可以并且会说这些函数是危险的。而且它们确实是危险的;所有浏览器和大多数扩展程序都禁止在普通JavaScript中使用它们,这是有原因的。...用户应该知道(警告可能会说明)仅仅因为它是危险的,并不意味着它一定被用于邪恶目的。(否则,我为什么要创建这个函数呢?) - Brock Adams
@WladimirPalant,这是一个扩展/插件环境,而不是浏览器页面的JavaScript/DOM。我不知道脚本编写者如何重命名我的函数,但我不是专业的扩展编写者。我将使用“编译时”或“安装时”检查,但它们不能防止运行时的漏洞,例如eval - Brock Adams
@BrockAdams:我不明白环境在这里有什么关系。脚本编写者仍然可以通过将其分配给本地变量而不“明确提及”其名称的方式间接调用任何函数。也许没有window变量,但是可以使用this代替。坦率地说,我认为控制“危险”API使用的唯一正确方法是首先不要公开这些API-也许应该暴露代替物,以显示警告。 - Wladimir Palant
2个回答

4

邪恶脚本编写者可以用什么方法来欺骗对受限函数使用的检查?

有成千上万种组合方式,例如使用 eval()new Function()String.fromCharCode()decodeURI() 的组合(就像您的示例中一样)。

我该如何防止这种恶作剧?

您能否重载/屏蔽特定的 函数/对象/变量?

GM_openSQL_Connection = function() {
   warnUser();
};

为了在扩展尝试访问禁止函数或变量时设置一个标志,只需有一个var isDangerous = false,如果调用了禁止函数或访问/修改了禁止属性的get/set,则将其设置为true
如果isDangeroustrue,那么您可以将该扩展标记为可能具有危险的函数/属性调用/访问。

嗯,这种阴影技术很有潜力。我可以要求开发人员自报他们在代码中使用的危险函数。用户将在安装时得到警告,并且运行时警告将对该脚本停用。任何未声明的函数仍会触发运行时警告,并且这将是更加明显的欺诈或粗心编码的证据。 - Brock Adams
遮蔽特定的不良函数是黑名单,这有点令人担忧。很可能你的黑名单会不完整。黑名单往往是脆弱的。 - D.W.
1
@D.W.,我不明白你的意思。我正在编写这些函数,并且完全控制它们的运行时行为(除了我不知道的安全漏洞)。脚本编写者如何绕过这个呢? - Brock Adams
如果你只暴露已知的好函数,那么你就很好(白名单)。如果你暴露了所有东西,但是又遮蔽了已知的坏函数,那就是脆弱的(黑名单)。通常,在Javascript中,默认情况下可以访问所有内容,而且无法防止不受信任的代码访问所有内容(通过全局对象)。Firefox扩展允许使用evalInSandbox,它允许调用者指定一个不同的全局对象。如果您使用evalInSandbox来指定仅公开已知的好函数的全局对象,则状态良好--但是您不需要遮蔽。 - D.W.
也许“shadowing”不是正确的术语,但这个答案启发了迄今为止看起来最好的方法...也就是说,函数本身会警告用户(并且可能会中止脚本),除非在“清单”中预先指示(在这种情况下,用户只会收到较轻的安装时警告)。 - Brock Adams
@BrockAdams 我称其为有意的 shadowing,而非故意的 clobbering :) - alex

2
尝试扫描脚本以检测是否使用了这些接口是错误的方法。通过混淆,很容易逃避检测,正如您所发现的那样。这是根本不安全的:没有办法让它起作用。
以下是更好的方法。要求脚本编写者包含一个清单,声明需要访问哪些特殊API。然后,在安全的Javascript沙盒中运行脚本,该沙盒仅公开允许的API和请求的API,但不提供其他内容。如果脚本在其清单中未请求GM_openSQL_Connection,则不向脚本公开该API。
因为Javascript是一种允许猴子补丁和无限制访问全局对象的动态语言,所以构建一个限制脚本可以访问哪些API的安全沙盒需要一些工作。因此,我建议您使用现有的沙盒解决方案。一种方法是在沙盒中运行用户脚本,并为受保护的API提供一个库,其中存放着敏感API的存根,这些存根只是使用postMessage向您的扩展代码发送RPC请求。这避免了跨越沙盒边界的引用,这很好,因为(取决于沙盒技术)这些类型的引用通常具有安全漏洞的潜在可能。
然后,您可以根据清单内容驱动用户警告。重要提示:请从用户的角度仔细考虑此事。普通用户能理解这些警告吗?他们能做出明智的决定吗?用户是否比您更有能力做出正确的决定?用户是否会因不断的警告而感到不堪重负,并开始忽略它们并单击“确定”(狼来了效应)?
有关Javascript沙盒技术的信息,请阅读IT Security上的以下问题:如何扫描恶意代码的Javascript?。将来,您可能会在IT Security网站上获得此类问题的答案。

这违背了我迄今为止所经历或阅读的一切。请提供一个参考或示例,证明/表明脚本代码能够访问扩展代码(而不是内容脚本代码),超出扩展可能提供的API范围。 - Brock Adams
这并不完全是架构,也不是Greasemonkey的操作方式。用户脚本只安装一次,不会在运行时下载(无论是否关闭更新)。而且它不仅仅是使用eval。在应用一些安全限制后,它使用evalInSandbox来运行。如果我理解正确的话,Chrome也使用了类似的机制。您的评论可能仍然适用,但我还没有看到文档或示例。 - Brock Adams
@BrockAdams,说得好!我的错误。我撤回了关于需要特殊沙盒技术(如Caja)的说法。我完全忘记了evalInSandbox,所以显然我并不像我想象的那么了解情况。对于我的错误,我深表歉意。 - D.W.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接