从 chrome 扩展访问 iframe [英] Accessing iframe from chrome extension

查看:229
本文介绍了从 chrome 扩展访问 iframe的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个 chrome 扩展程序,但遇到了一个大问题.

I'm developing a chrome extension and bumped into a big problem.

我正在使用内容脚本在网站上注入我的 javascript 代码.该网站有一个 iframe.我可以更改 iframe 的源代码,但似乎无法访问 iframe 的 contentWindow 属性.我需要它在当前插入位置插入文本.

I'm using content scripts to inject my javascript code on a web site. The web site has an iframe. I can change the source code of the iframe but don't seem to get any access to the iframe's contentWindow property. I need it to insert text at the current carret position.

所以基本上这段代码在页面上下文中完美运行:

So basically this code works perfectly in the context of the page:

$("#iframe1").contentWindow.document.execCommand("InsertHTML", false, 'test text');

但是当我尝试在我的 chrome 扩展的上下文中运行时,我收到此错误:

But when I try it to run in the context of my chrome extension I get this error:

TypeError: Cannot read property 'document' of undefined

奇怪的是我可以访问 iframe 的 html.所以这段代码在 chrome 扩展中完美运行:

What's strange is that I can access the html of the iframe. So this code works perfectly from the chrome extension:

$("#iframe1").contents().find('div').html('test')

我尝试将 "all_frames": true 放在清单文件中,但没有运气:(

I tried putting "all_frames": true in the manifest file but no luck :(

推荐答案

要了解为什么您的代码不起作用,我添加了 我之前回答的一个片段:

To understand why your code does not work, I include a fragment of my previous answer:

内容脚本无法访问页面的全局 window 对象.对于内容脚本,以下内容适用:

Content scripts do not have any access to a page's global window object. For content scripts, the following applies:

  • window 变量不引用页面的全局对象.相反,它指的是一个新的上下文,页面上的一个层".页面的 DOM 是完全可访问的.#execution-environment

给定一个由   组成的文档<iframe id="frameName" src="http://domain/"></iframe>:

Given a document consisting of   <iframe id="frameName" src="http://domain/"></iframe>:

  • 对框架内容的访问受到页面同源政策的限制;您的扩展程序的权限并未放宽政策.
  • frames[0]frames['frameName'],(通常是指包含全局 window 对象的框架)是 未定义.
  • var iframe = document.getElementById('frameName');
    • iframe.contentDocument 返回包含框架的 document 对象,因为内容脚本可以访问页面的 DOM.当同源策略适用时,此属性为 null.
    • iframe.contentDocument.defaultView(指与文档关联的window 对象)未定义.
    • iframe.contentWindow 未定义.
    • Access to the contents of a frame is restricted by the Same origin policy of the page; the permissions of your extension does not relax the policy.
    • frames[0] and frames['frameName'], (normally referring to the the frame's containing global window object) is undefined.
    • var iframe = document.getElementById('frameName');
      • iframe.contentDocument returns a document object of the containing frame, because content scripts have access to the DOM of a page. This property is null when the Same origin policy applies.
      • iframe.contentDocument.defaultView (refers to the window object associated with the document) is undefined.
      • iframe.contentWindow is undefined.

      同源帧的解决方案

      在您的情况下,以下任一方法都适用:

      Solution for same-origin frames

      In your case, either of the following will work:

      // jQuery:
      $("#iframe1").contents()[0].execCommand( ... );
      
      // VanillaJS
      document.getElementById("iframe1").contentDocument.execCommand( ... );
      
      // "Unlock" contentWindow property by injecting code in context of page
      var s = document.createElement('script');
      s.textContent = 'document.getElementById("iframe1").contentWindow.document.execCommand( ... );';
      document.head.appendChild(s);
      

      通用解决方案

      通用的解决方案是在清单文件中使用 "all_frames": true,并使用如下内容:

      if (window != top) {
          parent.postMessage({fromExtension:true}, '*');
          addEventListener('message', function(event) {
              if (event.data && event.data.inserHTML) {
                  document.execCommand('insertHTML', false, event.data.insertHTML);
              }
          });
      } else {
          var test_html = 'test string';
          // Explanation of injection at https://stackoverflow.com/a/9517879/938089 :
          // Run code in the context of the page, so that the `contentWindow`
          //  property becomes accessible
          var script = document.createElement('script');
          script.textContent = '(' + function(s_html) {
              addEventListener('message', function(event) {
                  if (event.data.fromExtension === true) {
                      var iframe = document.getElementById('iframe1');
                      if (iframe && (iframe.contentWindow === event.source)) {
                          // Window recognised, post message back
                          iframe.contentWindow.postMessage({insertHTML: s_html}, '*');
                      }
                  }
              });
          } + ')(' + JSON.stringify(test_html) + ');';
          (document.head||document.documentElement).appendChild(script);
          script.parentNode.removeChild(script);
      }
      

      此演示仅用于教育目的,请勿在实际扩展中使用此演示.为什么?因为它使用 postMessage 来传递消息.这些事件也可以由客户端生成,从而导致安全漏洞(XSS:任意 HTML 注入).

      This demo is for educational purposes only, do not use this demo in a real extension. Why? Because it uses postMessage to pass messages around. These events can also be generated by the client, which causes a security leak (XSS: arbitrary HTML injection).

      postMessage 的替代方案是 Chrome 的消息 API.如需演示,请参阅此答案.但是,您将无法比较 window 对象.你可以做的是依赖window.name属性.window.name 属性会自动设置为 iframe 的 name 属性的值(仅在加载 iframe 时设置一次).

      The alternative to postMessage is Chrome's message API. For a demo, see this answer. You won't be able to compare the window objects though. What you can do is to rely the window.name property. The window.name property is automatically set to the value of the iframe's name attribute (just once, when the iframe is loaded).

      这篇关于从 chrome 扩展访问 iframe的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆