【问题标题】:Firefox Addon SDK: Loading addon file into iframeFirefox 插件 SDK:将插件文件加载到 iframe
【发布时间】:2014-01-13 00:27:29
【问题描述】:

我想将resource:// 链接,分别从我的Firefox 插件加载到网页中的iframe 中的本地文件。

原因是,出于安全原因,资源应该以可视方式嵌入到网页中,同时不允许网站访问它的 DOM。

过去曾在不同的地方讨论过这个问题,例如这里(没有解决方案): https://bugzilla.mozilla.org/show_bug.cgi?id=792479

由于大多数帖子都比较旧,我想问一下,在此期间是否有任何新的解决方案或解决方法。

【问题讨论】:

    标签: javascript firefox iframe firefox-addon firefox-addon-sdk


    【解决方案1】:

    我想我在错误或 ML 中建议了一个糟糕的解决方法,基本上是将您的 resource:// 转换为 data: url(使用 data.load 加载 HTML 内容,然后编码并附加作为前缀,所以这样的东西应该可以工作:

    /* main.js */
    const { data } = require('sdk/self');
    
    // just an example, you can use `tab.attach` too
    require('sdk/page-mod').PageMod({
      include: '*',
      contentScriptFile: data.url('content.js'),
      contentScriptOptions: {
        content: encodeURIComponent(data.load('index.html'))
      }
    });
    
    /* content.js */
    let iframe = document.body.appendChild(document.createElement('iframe'));
    
    iframe.setAttribute('sandbox', 'allow-scripts');
    // maybe you want also use the seamless attribute, see:
    // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe
    
    iframe.contentWindow.location.href = 'data:text/html;charset=utf-8,' + self.options.content;
    

    当然,这是一种解决方法,我希望您提到的错误将很快得到修复。 请注意,通过这种方式,您无法直接从 iframe 与父文档进行通信,但这也意味着您无法绕过,这就是您想要阻止的。

    当然,您仍然可以使用附加代码在您的 iframe 和父文档之间进行通信(您需要附加内容脚本并使用 portpostMessage)。

    编辑: 更改了 url 的设置方式,否则从父文档中获取 src 属性仍然是可能的,并且包含整个 HTML。

    【讨论】:

    • 谢谢。父文档不能通过删除沙盒属性重新获得对 iframe 内容的访问权限吗?
    • 编辑:不,它不能。对 sandbox 属性的更改仅适用于重新加载页面。
    • 随着最近对 Jetpack API 的所有增强,这仍然是使这种 iframe 功能正常工作的最佳技术吗?
    • 我仍然看到,如果我们尝试将 resource:// 设置为 iframe 的 src,它永远不会加载。但是我想要添加的目标页面有 CSP 来阻止 frame-src 模式数据:我正在使用 Firefox AddOn sdk。
    • 在某些页面(例如 gmail 和 github)上,我遇到了这个解决方案的错误:“...result = 2153644038”
    【解决方案2】:

    我用a solution proposed here

    它是通过创建一个特殊的协议来实现的,该协议由您的 Firefox 插件处理,然后从其文件夹中请求资源。
    请注意,如果资源文件夹可能包含非公开内容,那么我会添加额外的检查,以仅允许这些真正打算通过 Web 访问的资源。

    上面提到的帖子所附的自定义协议代码是available here

    /*
    Makes any file within the data directory available to use in an iframe.
    Replace this: require("sdk/self").data.url(...)
    With this: require("name-of-this-file").url(...)
    */
    var { Class } = require('sdk/core/heritage');
    var { Unknown, Factory } = require('sdk/platform/xpcom');
    var { Cc, Ci, Cr } = require('chrome');
    var self = require("sdk/self");
    
    var resourceProtocolHandler = Cc["@mozilla.org/network/io-service;1"]
        .getService(Ci.nsIIOService)
        .getProtocolHandler('resource');
    
    var scheme = "res-" + self.id.toLowerCase().replace(/[^a-z0-9+\-\.]/g, "-");
    
    var AddonProtocolHandler = Class({
        extends: Unknown,
        interfaces: ['nsIProtocolHandler'],
    
        scheme: scheme,
        defaultPort: -1,
        protocolFlags: Ci.nsIProtocolHandler.URI_STD
            | Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE
            | Ci.nsIProtocolHandler.URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT,
    
        newURI: function(spec, originCharset, baseURI) {
            let uri = Cc["@mozilla.org/network/standard-url;1"].createInstance(Ci.nsIStandardURL);
            uri.init(uri.URLTYPE_STANDARD, this.defaultPort, spec, originCharset, baseURI);
            return uri.QueryInterface(Ci.nsIURI);
        },
    
        newChannel: function(uri) {
            if (uri.spec.indexOf(exports.url("")) != 0) {
                throw Cr.NS_ERROR_ILLEGAL_VALUE;
            }
            var resourceUri = resourceProtocolHandler.newURI(uri.spec.replace(scheme + "://", "resource://"), uri.originCharset, null);
            var channel = resourceProtocolHandler.newChannel(resourceUri);
            channel.originalURI = uri;
            return channel;
        },
    
        allowPort: (port, scheme) => false
    });
    
    Factory({
        contract: "@mozilla.org/network/protocol;1?name=" + scheme,
        Component: AddonProtocolHandler
    });
    
    exports.url = function(url) {
        return self.data.url(url).replace("resource://", scheme + "://");
    };
    

    附加说明:对于page 脚本(不是content 脚本),此自定义协议有助于加载iframe 和其他HTML 元素,但不能加载XMLHttpRequest 或@ 987654328@。对于后者,仍然适用跨域限制并引发安全错误:“访问受限 URI 被拒绝”XMLHttpRequest 和“操作不安全”。为Worker
    相比之下,在 Chrome 下,XMLHttpRequestweb_accessible_resources 是允许的。 Worker 在 Chrome 下也没有实现对 web_accessible_resources 的访问。
    但是对于Workers,您可以将此自定义协议网址用于importScripts 方法。使用它,您还可以解决将自定义资源加载到Workers 的问题。此代码也适用于 Chrome,作为使用 XMLHttpRequest 的替代方法。

    var code = "self.onmessage = function (message)\
    {\
        self.onmessage = null;\
        self.importScripts(message.data);\
    };";
    
    var blob = new Blob([code], {type: 'application/javascript'});
    var blobUrl = URL.createObjectURL(blob);
    var w = new Worker(blobUrl);
    w.postMessage(*webAccessibleResourceUrl*);
    URL.revokeObjectURL(blobUrl);
    

    【讨论】:

      【解决方案3】:

      我正在使用zer0 的想法。但是,在具有内容安全策略的页面上,我遇到了异常(...结果 = 2153644038)。 因此,我将我的域添加到响应标头的 content-security-policy 中:

      //main.js 
      var { Cc, Ci } = require('chrome');
      
      var observer = {
          observe : function(aSubject, aTopic, aData) {
            if (aTopic == "http-on-examine-response") {
              aSubject.QueryInterface(Ci.nsIHttpChannel);
              var csp = aSubject.getResponseHeader("content-security-policy");
              if(csp.indexOf('frame-src') > -1) {
                  var cspParts = csp.split(';');
                  for (var i=0; i<cspParts.length; i++) {
                      if(cspParts[i].indexOf('frame-src') > -1) {
                          cspParts[i] += ' yourdomain.tld';
                          break;
                      }
                  }
                  aSubject.setResponseHeader("content-security-policy", cspParts.join(';'), false);
              } 
            }
          }
      }; 
      var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
      observerService.addObserver(observer, "http-on-examine-response", false);
      
      //content-script.js 
      iframe.src = yourdomain.tld/...
      

      编辑:此代码可能会被 FF 审阅者拒绝:“出于安全原因,不允许修改 'content-security-policy'。”

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多