JavaScript: 检测/防止外部脚本

6

是否可能检测到由浏览器插件、代理、xss等加载到页面的外部脚本?

假设我有这个网页:

<html>
    <head>
        <title>Hello world!</title>
        <script src="http://mydomain.com/script.js"></script>
    </head>
    <body>
        Hello world!
    </body>
</html>

我是否可以在我的script.js文件中包含一些脚本,以便检测页面上的其他脚本元素是否不是来自http://mydomain.com

我想要一些能够检测其他脚本的东西,无论它们是如何被包含在源代码中的(即它们在onload事件触发时存在),还是在页面加载后添加的。

如果我能够检测到这些脚本,那么我也能够阻止它们吗?

如果我知道有其他东西正在进行,那么这对于调试用户报告的javascript/ui问题非常有用。

我使用jQuery,所以jQuery的答案对我有效。我只是不想将答案限制在仅使用jQuery上。


编辑

我的解决方案如下。但是,它存在两个(潜在的)问题:

  1. 它依赖于jQuery。
  2. 它无法检测通过CSS @import规则(或任何带有url()值的规则)加载的外部资源。

如果有人想提交一个解决这些问题中的一个或两个的答案,我会点赞。

如果您解决了这两个问题,我将接受您的答案。

4个回答

3
您可以在domready时像这样检查所有脚本元素:
$(function () {
    $('script').each(function () {
        check script source here
    })
})

但是,如果有人能够在你的网站中注入脚本标签,他也可以在你开始检查之前删除你的代码,而且很难删除脚本可能创建的对象和函数,直到你意识到它们存在。所以我认为,在这个领域投资时间并不是一个好的解决方案。更重要的是要清楚地知道,无论如何你都不能信任客户端。
如果你仍然想弄清楚,有一堆DOM事件可以检查DOM树是否已经改变。

你第二段提到的观点很好。我已经在问题中添加了我的理由。这不仅仅是为了安全,更多的是为了错误报告。 - Andrew Ensley
我希望我能再次点赞,仅因为提供了指向Mozilla Javascript文档的链接。 - Andrew Ensley

1

虽然我感激Andreas Köberle的建议,但我还是对得到的答案不满意,所以我决定自己来解决。

我编写了一个函数,可以随时运行,并识别任何带有外部来源的html元素。这样,我就可以在报告javascript错误时运行此函数,以获取更多关于环境的信息。

代码

依赖于jQuery (抱歉,元素选择只是更容易),以及 parseUri()(复制在此答案底部)。

/**
 * Identifies elements with `src` or `href` attributes with a URI pointing to
 * a hostname other than the given hostname. Defaults to the current hostname.
 * Excludes <a> links.
 * 
 * @param string myHostname The hostname of allowed resources.
 * @return array An array of `ELEMENT: src` strings for external resources.
 */
function getExternalSources(myHostname)
{
    var s, r = new Array();
    if(typeof myHostname == 'undefined')
    {
        myHostname = location.hostname;
    }
    $('[src], [href]:not(a)').each(function(){
        s = (typeof this.src == 'undefined' ? this.href : this.src);
        if(parseUri(s).hostname.search(myHostname) == -1)
        {
            r.push(this.tagName.toUpperCase() + ': ' + s);
        }
    });
    return r;
}

使用方法

var s = getExternalSources('mydomain.com');
for(var i = 0; i < s.length; i++)
{
    console.log(s[i]);
}

// Can also do the following, defaults to hostname of the window:
var s = getExternalSources();

搜索包括子域名,因此在上面的示例中,具有源为www.mydomain.comimg.mydomain.com的元素将被允许。
请注意,这不会捕获CSS @import规则中的外部源(或任何带有url()的CSS规则)。如果有人想贡献可以做到这一点的代码,我将支持并接受您的答案。
以下是 parseUri() 的代码,我从 https://gist.github.com/1847816 获取并稍作修改。
(function(w, d){
    var a,
        k = 'protocol hostname host pathname port search hash href'.split(' ');
    w.parseUri = function(url){
        a || (a = d.createElement('a'));
        a.href = url;
        for (var r = {}, i = 0; i<8; i++)
        {
            r[k[i]] = a[k[i]];
        }
        r.toString = function(){return a.href;};
        r.requestUri = r.pathname + r.search;
        return r;
    };
})(window, document);

1
请注意,<script>包含可以添加并立即从DOM中删除。这意味着该方法无法捕获它。将其作为DOMNodeInserted事件的一部分添加可能会很有用。 - Lee Davis

0

您可以监听DOM的变化,看看是否插入了新的脚本标签。但我想问,这样做的原因是什么?我怀疑您将无法检测到执行任意JS针对您页面DOM的所有可能情况(例如书签工具或Greasemonkey脚本)。


2
出于以下原因:
  1. 只是想看看我能不能做到 :-)
  2. 如果我知道还有其他事情在进行中,那么在调试用户报告的javascript/ui问题时会很有用。编辑:此外,我并不真正关心书签脚本甚至是油猴脚本。用户知道他们正在点击书签脚本,而油猴用户如果出现问题,很可能会理解是什么导致了问题。我主要想适应那些安装了“$$终极优惠券$$”插件加载外部脚本的无知用户。
- Andrew Ensley

0

3
这仅适用于 AJAX 请求。我所说的是页面上具有外部来源的脚本元素,这是 JSONP 的基础。 - Andrew Ensley
你可以检查元素是否绑定了事件:https://dev59.com/vnI_5IYBdhLWcg3wHvU5 - matpol

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