【问题标题】:Security Error when trying to load content from resource in a Firefox Addon (SDK)尝试从 Firefox 插件 (SDK) 中的资源加载内容时出现安全错误
【发布时间】:2014-02-21 23:48:24
【问题描述】:

我正在使用 SDK 创建一个 firefox 插件。我的目标很简单,拦截特定的 iframe 并加载我自己的 HTML 页面(使用我的插件打包为资源)而不是最初请求的内容。

到目前为止,我有以下代码:

var httpRequestObserver = 
{
    observe: function(subject, topic, data)
    {
        var httpChannel, requestURL;

        if (topic == "http-on-modify-request") {
            httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
            requestURL = httpChannel.URI.spec;

            var newRequestURL, i;

            if (/someurl/.test(requestURL)) {
                var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);

                httpChannel.redirectTo(ioService.newURI(self.data.url('pages/test.html'), undefined, undefined));
            }

            return;
        }
    }
};

var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
observerService.addObserver(httpRequestObserver, "http-on-modify-request", false);

此代码的工作原理是它检测到正确的 iframe 加载并正确执行重定向。但是,我收到以下错误:

安全错误:http://url.com 的内容可能无法加载或链接到 jar:file:///.../pages/test.html.

我怎样才能绕过这个限制?

【问题讨论】:

    标签: firefox-addon firefox-addon-sdk


    【解决方案1】:

    其实我是真的想多了。

    当我改用 loadContext 时,它已经解决了。现在,当您获得 loadContext 时,您将获得任何浏览器元素(标签浏览器、框架或 iframe)的 contentWindow,然后像您正在做的那样中止 http 请求,然后 loadContext.associatedWindow.document.location = self.data('pages/tests.html');

    完成

    将代码粘贴到此处,删除所有私有内容。您可能需要 chrome.manifest 对其进行测试并将代码粘贴回此处

    Cu.import('resource://gre/modules/Services.jsm');
    
    var httpRequestObserver = {
        observe: function (subject, topic, data) {
            var httpChannel, requestURL;
    
            if (topic == "http-on-modify-request") {
                httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
                requestURL = httpChannel.URI.spec;
    
                var newRequestURL, i;
    
                if (/someurl/.test(requestURL)) {
                    var goodies = loadContextGoodies(httpChannel);
                    if (goodies) {
                        httpChannel.cancel(Cr.NS_BINDING_ABORTED);
                        goodies.contentWindow.location = self.data.url('pages/test.html');
                    } else {
                        //dont do anything as there is no contentWindow associated with the httpChannel, liekly a google ad is loading or some ajax call or something, so this is not an error
                    }
                }
    
                return;
            }
        }
    };
    Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
    
    
    
    
    
    //this function gets the contentWindow and other good stuff from loadContext of httpChannel
    function loadContextGoodies(httpChannel) {
        //httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
        //start loadContext stuff
        var loadContext;
        try {
            var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
            //var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
            try {
                loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
            } catch (ex) {
                try {
                    loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
                } catch (ex2) {}
            }
        } catch (ex0) {}
    
        if (!loadContext) {
            //no load context so dont do anything although you can run this, which is your old code
            //this probably means that its loading an ajax call or like a google ad thing
            return null;
        } else {
            var contentWindow = loadContext.associatedWindow;
            if (!contentWindow) {
                //this channel does not have a window, its probably loading a resource
                //this probably means that its loading an ajax call or like a google ad thing
                return null;
            } else {
                var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIWebNavigation)
                    .QueryInterface(Ci.nsIDocShellTreeItem)
                    .rootTreeItem
                    .QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIDOMWindow);
                var gBrowser = aDOMWindow.gBrowser;
                var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
                var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
                return {
                    aDOMWindow: aDOMWindow,
                    gBrowser: gBrowser,
                    aTab: aTab,
                    browser: browser,
                    contentWindow: contentWindow
                };
            }
        }
        //end loadContext stuff
    }
    

    注意:现在先试试这个,我还没有测试它,如果在尝试重定向时遇到安全错误,则创建一个 chrome.manifest 文件并将其放在根目录中.如果它引发了安全错误,那么您肯定需要一个 chrome.manifest 文件,这将毫无疑问地修复它。今晚晚些时候我会自己测试一下。

    chrome.manifest 应该如下所示:

    content kaboom-data ./resources/kaboom/data/ contentaccessible=yes
    

    然后在上面的代码方式中将重定向行从goodies.contentWindow.location = self.data.url('pages/test.html');更改为goodies.contentWindow.location = 'chrome://kaboom-data/pages/test.html');

    【讨论】:

    • 我也采用了这种方法。问题是,在我的情况下,我试图捕获 iframe 的导航(与此代码一起使用),然后仅重定向 iframe(而不是顶部窗口)。提供的代码尝试导航顶部窗口而不是 iframe。我尝试了这种方法: loadContext.associatedWindow.frameElement.src = 'chrome://kaboom-data/content/test.html';即使使用 chrome.manifest 也会产生相同的安全错误
    • 你确定吗?毫无疑问, loadContext.associatedWindow 是加载的内容窗口,因此它是 iframe 或框架或顶部窗口。我不是在这个范围内而是在以前测试过它。你能告诉我如何重现你的情况来测试一下吗
    • 几周前我在 loadContext 上进行了极其繁重的测试,以及它如何获取实际加载位置的窗口,可以在 herehere 找到。现在,如果您真的不想这样做,那么您可以求助于添加事件侦听器,如 here 所示,或者您可以使用 Web 进度侦听器,您也可以使用 documjent-element-inserted 观察器,如 here 所示。 loadContext 是最简单的
    • 你是对的。 contentWindow.location 按预期工作。谢谢。
    • 哇哦我的第一个赏金!谢谢你,兄弟!! :) 我也从帮助你中学到了很多东西! :) 确保您注意加载到顶部窗口的资源或与您匹配的相同 URL 模式的东西,这可能是一开始就让您失望的原因。就像如果您匹配“google”的 url 模式并且顶部窗口加载了 google.com/img.png 这将为您提供顶部窗口,因此请确保将它们过滤掉
    【解决方案2】:

    在此处查看此插件:https://addons.mozilla.org/en-US/firefox/addon/ghforkable/?src=search

    在 chrome.manifest 文件中,我们将 contentaccessible 参数设置为 yes

    此插件不需要 sdk。它是如此简单,只需将其粘贴到引导程序骨架中,如下所示:

    Bootstrap With Some Features, Like chrome.manifest which you will need

    Bootstrap Ultra Basic

    如果您真的想将页面重定向到您的网站,也许您想自定义页面?如果您想为您制作一个关于自定义页面的演示。你可以看到有点难以理解的演示here

    【讨论】:

    • 不幸的是,这并不能帮助我克服困难。我已经在插件中实现了其他功能,因此我很难在不使用 SDK 的情况下返回并重新开始。 -- 在将互联网 iframe 重定向到本地资源时,设置内容策略似乎会有所帮助。
    • 把你的插件上传到 github(我更喜欢 github,但其他的也可以),我为你设置好了。
    • 已上传。我已邀请您访问我的私人仓库。
    • 谢谢你能不能把它打包成xpi以便我可以安装,我不知道如何在没有install.rdf的情况下安装addon-sdk插件
    【解决方案3】:

    在这里发布我的试验,以便对所有人有所帮助:

    trail 1 失败 - 创建 chrome.manifest 文件,内容为 content kaboom-data resources/kaboom/data/ contentaccessible=yes

    var myuri = Services.io.newURI('chrome://kaboom-data/content/pages/test.html', undefined, undefined);
    httpChannel.redirectTo(myuri);
    

    抛出错误

    安全错误:http://digg.com/tools/diggthis/confirm 的内容?可能 不加载或链接到 jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ@jetpack.xpi!/resources/kaboom/data /pages/test.html.

    试用 2 失败 - 在 bootstrap.js 中创建资源

    别名.spec = file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ@jetpack.xpi

    别名已更新为规范: jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ@jetpack.xpi!/

       let resource = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
      let alias = Services.io.newFileURI(data.installPath);
      Cu.reportError('alias.spec = ' + alias.spec);
      if (!data.installPath.isDirectory()) {
        alias = Services.io.newURI("jar:" + alias.spec + "!/", null, null);
        Cu.reportError('alias updated to spec: ' + alias.spec);
      }
      resource.setSubstitution("kaboom_data", alias);
    

    ...

    var myuri = Services.io.newURI('resource://kaboom_data/resources/kaboom/data/pages/test.html', undefined, undefined);
    httpChannel.redirectTo(myuri);
    

    抛出错误

    安全错误:http://digg.com/tools/diggthis/confirm 的内容?可能 不加载或链接到 jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ@jetpack.xpi!/resources/kaboom/data /pages/test.html.

    结论 在上面的两个试验中,这是最奇怪的事情,它不会在抛出的安全错误中显示资源或 chrome 路径,但它会给出完整的 jar 路径。让我相信这与 redirectTo 功能有关。

    有效的解决方案是你的解决方案

    var gBrowser = utils.getMostRecentBrowserWindow().gBrowser;
    var domWin = httpChannel.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
    var browser = gBrowser.getBrowserForDocument(domWin.document);
    
    //redirect
    browser.loadURI(self.data.url('pages/test.html'));
    

    但是我将其更改为使用 loadContext 而不是此方法,因为这是推荐的方法。如果 url 加载缓慢并且在那个时候用户切换到另一个选项卡或窗口,gBrowser 到 getMostRecentBrowserWindow 也会失败

    我也改为使用 Services.jsm,因为无论如何你已经导入了 Cu。使用 Services.jsm 非常快,甚至连眨眼都不快。它只是一个指针。

    我仍在努力尝试使用 redirectTo 方法,它真的让我很困扰。我所做的更改是针对我的本地副本。

    【讨论】:

    • 实际上,如果您在 html 中创建 iframe 并将其设置为 chrome 路径,即使 contentaccessible 它也不会加载。它与安全性有关 HERE 有一种方法可以将其列入白名单,也许 @WladimirPalant 在他写那篇文章时可以在这里提供帮助
    • 也关注了我寻求帮助的这个主题,发现与我们将 iframe 的 src 设置为 chrome 位置时类似的问题。 url to topic
    • 好吧,我做不到,我试了很多次。让我给你我的代码,因为它是一个私人仓库,我应该如何给你代码?该代码显示了如何使用 loadContext 和 Services.jsm
    【解决方案4】:

    您是否考虑过将本地 HTML 文件转换为数据 URL 并加载它?

    【讨论】:

    • 是的。问题是我无法引用关联的 JS/CSS 文件。我必须将所有内容嵌入到一个 html 文件中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    • 2021-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多