SecurityError:阻止具有源的框架访问跨域框架

我正在我的 HTML 页面中加载 <iframe> 并尝试使用 Javascript 访问其中的元素,但是当我尝试执行我的代码时,我收到以下错误:

I am loading an <iframe> in my HTML page and trying to access the elements within it using Javascript, but when I try to execute my code, I get the following error:

SecurityError: Blocked a frame with origin "http://www.<domain>.com" from accessing a cross-origin frame.

您能帮我找到一个解决方案,以便我可以访问框架中的元素吗?

Can you please help me to find a solution so that I can access the elements in the frame?

我正在使用此代码进行测试,但徒劳无功:

I am using this code for testing, but in vain:

$(document).ready(function() {
    var iframeWindow = document.getElementById("my-iframe-id").contentWindow;

    iframeWindow.addEventListener("load", function() {
        var doc = iframe.contentDocument || iframe.contentWindow.document;
        var target = doc.getElementById("my-target-id");

        target.innerHTML = "Found it!";
    });
});

推荐答案

同源策略

你不能使用 JavaScript 访问不同来源的 <iframe>,如果你能做到,那将是一个巨大的安全漏洞.对于 同源策略 浏览器阻止脚本试图访问具有不同来源的框架.

Same-origin policy

You can't access an <iframe> with different origin using JavaScript, it would be a huge security flaw if you could do it. For the same-origin policy browsers block scripts trying to access a frame with a different origin.

如果地址的以下至少一个部分没有得到维护,则认为来源不同:

Origin is considered different if at least one of the following parts of the address isn't maintained:

protocol://hostname:port/...

如果您要访问框架,协议、主机名和端口必须与您的域相同.

Protocol, hostname and port must be the same of your domain if you want to access a frame.

注意:众所周知,Internet Explorer 并未严格遵守此规则,请参阅 这里 了解详情.

NOTE: Internet Explorer is known to not strictly follow this rule, see here for details.

以下是尝试从 http://www.example.com/home/index.html

URL                                             RESULT 
http://www.example.com/home/other.html       -> Success 
http://www.example.com/dir/inner/another.php -> Success 
http://www.example.com:80                    -> Success (default port for HTTP) 
http://www.example.com:2251                  -> Failure: different port 
http://data.example.com/dir/other.html       -> Failure: different hostname 
https://www.example.com/home/index.html:80   -> Failure: different protocol
ftp://www.example.com:21                     -> Failure: different protocol & port 
https://google.com/search?q=james+bond       -> Failure: different protocol, port & hostname 

解决方法

即使同源策略阻止脚本访问具有不同来源的站点的内容,如果您拥有这两个页面,则可以使用 window.postMessage 及其相关的 message 事件 在两个页面之间发送消息,如下所示:

Workaround

Even though same-origin policy blocks scripts from accessing the content of sites with a different origin, if you own both the pages, you can work around this problem using window.postMessage and its relative message event to send messages between the two pages, like this:

  • 在您的主页中:

  • In your main page:

const frame = document.getElementById('your-frame-id');
frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.com');

postMessage() 的第二个参数可以是 '*' 以表明对目的地的来源没有偏好.应尽可能提供目标来源,以避免泄露您发送到任何其他网站的数据.

The second argument to postMessage() can be '*' to indicate no preference about the origin of the destination. A target origin should always be provided when possible, to avoid disclosing the data you send to any other site.

在您的 <iframe>(包含在主页中):

In your <iframe> (contained in the main page):

window.addEventListener('message', event => {
    // IMPORTANT: check the origin of the data! 
    if (event.origin.startsWith('http://your-first-site.com')) { 
        // The data was sent from your site.
        // Data sent with postMessage is stored in event.data:
        console.log(event.data); 
    } else {
        // The data was NOT sent from your site! 
        // Be careful! Do not use it. This else branch is
        // here just for clarity, you usually shouldn't need it.
        return; 
    } 
}); 

此方法可以双向应用,也可以在主页中创建一个监听器,并接收来自框架的响应.同样的逻辑也可以在弹出窗口和基本上由主页生成的任何新窗口中实现(例如,使用 window.open()) 也一样,没有任何区别.

This method can be applied in both directions, creating a listener in the main page too, and receiving responses from the frame. The same logic can also be implemented in pop-ups and basically any new window generated by the main page (e.g. using window.open()) as well, without any difference.

已经有一些关于这个主题的好答案(我刚刚发现他们在谷歌上搜索),所以,对于可能的浏览器,我将链接相关答案.但是,请记住禁用同源策略只会影响您的浏览器.此外,在禁用同源安全设置的情况下运行浏览器会授予 任何 网站对跨源资源的访问权限,因此 这是非常不安全的,如果您不确切知道自己是什么,则永远不要这样做做(例如开发目的).

There already are some good answers about this topic (I just found them googling), so, for the browsers where this is possible, I'll link the relative answer. However, please remember that disabling the same-origin policy will only affect your browser. Also, running a browser with same-origin security settings disabled grants any website access to cross-origin resources, so it's very unsafe and should NEVER be done if you do not know exactly what you are doing (e.g. development purposes).

  • 谷歌浏览器
  • Mozilla Firefox
  • Safari
  • 歌剧
  • Microsoft Edge:不可能
  • Microsoft Internet Explorer

相关文章