如何检测或防止内置浏览器功能被替换?
我今天注意到,我可以替换这样的敏感内置JS功能:
async function _hackedEncrypt(algorithm, key, data) {
console.log('hacked you!');
}
const subtle = global.crypto.subtle; // Assign to get around "read-only" error.
subtle.encrypt = _hackedEncrypt;
global.crypto.subtle.encrypt(); // 'Hacked you!' appears in console.
yikes!
这种利用是如此简单。我的Web应用程序中成千上万的依赖关系(直接和及时效率)都可以使此函数重新分配。请注意,我的问题不是特定于Web Crypto的问题 - 它只是攻击者最危险的目标之一。
如何检测该功能已被重新分配,或者保证我一直在称其为原始浏览器实现?
I noticed today that I can replace a sensitive built-in JS function like this:
async function _hackedEncrypt(algorithm, key, data) {
console.log('hacked you!');
}
const subtle = global.crypto.subtle; // Assign to get around "read-only" error.
subtle.encrypt = _hackedEncrypt;
global.crypto.subtle.encrypt(); // 'Hacked you!' appears in console.
Yikes!
This exploit is so simple. Any of the thousands of dependencies (direct and transitive) in my web app could make this function reassignment. Note that my question isn't specific to Web Crypto - it's just one of the more dangerous targets for an attacker.
How can I either detect that the function has been reassigned or guarantee that I'm always calling the original browser implementation of it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您所描述的是更广泛的攻击类别的子集:供应链攻击。
基本想法是,我创建了一个有用且琐碎的JS库,随着时间的流逝,大量的项目取决于它,然后我插入后门,下次他们升级它们是依赖性的 - 我可以访问他们的用户浏览器。
然后,我可以窃取密码,信用卡信息,PII等。-基本上是数字浏览。
magecart 可能是JS空间中最著名的攻击。 Probably the best known one in general is the Solarwinds attack.
一种解决方案是自己滚动。这几乎是绝望的,因为即使您可能知道使用了什么API,但您也不知道依赖性使用什么以及如何改变。
另一个解决方案是 content Security Policy 撇油器可能能够将其代码放入您的应用中,但是如果您的内容安全策略不允许其向未知主机发出请求,则他们将无法做任何有用的事情。
也有商业解决方案。我知道:
What you are describing is a subset of a broader class of attacks: Supply Chain Attacks.
The basic idea is that I create a JS library that is useful and trivial, over time a ton of projects depend on it, then I insert a back door, next time they upgrade they're dependencies - I have access to their users' browsers.
I can then steal passwords, credit card info, PII, etc. - basically digital skimming.
Magecart is probably being the best known attack in the JS space. Probably the best known one in general is the Solarwinds attack.
One solution is to roll your own. That is pretty much hopeless, because even though you might know what APIs you use, you don't know what your dependencies use, and how that changes.
Another solution is Content Security Policy, which controls outgoing requests: a skimmer might have been able to put their code in your app, but they can't do anything useful if your content security policy doesn't let it issue requests to unknown hosts.
There are also commercial solution. I'm aware of:
在我的
index.js
中,我在其他任何模块之前将此模块导入。它必须是第一个导入,以便其他依赖关系没有机会替换功能,然后才能设置对原始功能的引用。...然后我调用
wayfunctionsRepadice()
在我担心的函数呼叫之前:当然,我也可以包装受保护的功能,例如:
在某些情况下,它更方便将内置函数存储到变量上,并直接从变量中调用该函数,而不是
global。*
。但是对于crypto.subtle.encrypt
它将在Chrome中丢弃“不良调用”错误。更努力地思考它,许多微妙的,意外的行为可能是通过在全球层次结构中的预期位置之外调用内置功能来造成的。这是后代的自我招待者。但是我很想听听比这更好的解决方案。也欢迎对该解决方案的任何缺点批评。
In my
index.js
, I import this module ahead of any other modules. It must be the first import so that other dependencies don't get a chance to replace a function before I can set a reference to the original....and then I call
wereFunctionsReplaced()
ahead of the function call I'm worried about:Of course, I could also wrap the protected functions like:
In some cases, it would be more convenient to store the built-in function to a variable and call the function directly from the variable rather than from
global.*
. But forcrypto.subtle.encrypt
it will throw a "Bad invocation" error in Chrome. And thinking harder about it, many subtle, unexpected behaviors could be caused by calling the built-in functions outside their expected location in the global hierarchy.This is a self-answer for posterity. But I would love to hear better solutions than this one. Criticism on any faults this solution may have is welcome as well.