SecurityError:阻止源访问跨源帧

SecurityError: Blocked a frame with origin from accessing a cross-origin frame

提问人:mubashermubi 提问时间:8/3/2014 最后编辑:Mikemubashermubi 更新时间:11/7/2023 访问量:1664256

问:

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

SecurityError:阻止源“http://www.example.com”的帧访问跨源帧。

如何访问框架中的元素?

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

$(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 jquery 安全性 iframe 同源策略

评论

1赞 sideshowbarker 8/9/2021
window.postMessage() developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
1赞 Leslie Krause 12/12/2022
我实际使用并且仍然得到 OP 在尝试访问目标窗口时提到的错误。window.postMessage()event.source

答:

1156赞 Marco Bonelli 8/3/2014 #1

同源策略

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

如果未维护地址的以下至少一部分,则将源视为不同:

protocol://hostname:port/...

如果要访问帧,则域的协议、主机名和端口必须相同。

注意:虽然现在大部分人都没有使用,但众所周知,Internet Explorer并不严格遵守此规则,有关详细信息,请参阅此处

例子

以下是尝试从以下 URL 访问以下 URL 时发生的情况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 及其相对消息事件在两个页面之间发送消息来解决此问题,如下所示:

  • 在您的主页中:

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

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

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

    window.addEventListener('message', event => {
        // IMPORTANT: check the origin of the data!
        if (event.origin === 'https://your-first-site.example') {
            // 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()),没有任何区别。

在浏览器中禁用同源策略

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

评论

56赞 snappieT 1/14/2015
我发现的任何其他答案 12 都表明 CORS/ 不适用于 iFrame,仅适用于 XHR、Fonts、WebGL 和 canvas.drawImage。我相信是唯一的选择。Access-Control-Allow-OriginpostMessage
5赞 Marco Bonelli 10/17/2015
@SabaAhang只需检查 ,如果站点与您域的主机名不同,则无法访问该框架。iframe.src
2赞 Daniel Sokolowski 5/21/2016
对于简单情况,另一种解决方法是将 GET 参数作为 的一部分传递,并通过对象 ex 在接收端提取它们srclocation<iframe src='foobar.com/?sCSS=color%3Ared'></iframe>
4赞 Marco Bonelli 5/22/2018
@user2568374 是父帧的位置。如果你的帧在另一个站点内运行,并且你正在检查事件的源是否包含父帧地址,这总是真的,因此你允许任何具有任何源帧访问你的帧,这显然不是你想做的事情。此外,正如我在上面的评论中已经解释的那样,这也是不好的做法。location.ancestorOrigins[0]event.origin.indexOf(location.ancestorOrigins[0])document.referrer
2赞 Marco Bonelli 8/26/2022
@jub0bs感谢您指出这一点。难以置信的是,这样一段代码已经在那里坐了这么久。更新!
68赞 Geert 10/9/2014 #2

补充 Marco Bonelli 的回答:当前在帧/iframe 之间交互的最佳方式是使用 window.postMessage所有浏览器都支持

评论

19赞 VIJAY P 2/2/2017
window.postMessage 只有当我们能够同时访问父元素(我们的 HTML 页面)和子元素(其他域 iframe)时,我们才能使用。否则“没有可能”,它将始终抛出错误“Uncaught DOMException: Blocked a frame with origin ”<yourdomainname.com>“ from access a cross-origin frame.”
0赞 Leslie Krause 12/12/2022
除了这似乎不适用于本地文件。如果我在弹出窗口中执行此操作,则父窗口将无法访问 .我收到“阻止源为”null“的帧访问跨源帧。这是具有讽刺意味的,因为文档明确指出,postMessage 的全部意义在于允许跨不同来源的安全通信。window.opener.postMessage( { }, "*" );event.source
0赞 godhar 8/24/2023
我既无法绕过“用原点阻止帧”浏览器错误。你找到@LeslieKrause的方法了吗?我需要显示一个跨域 iframe,但 postMessage 没有成功。
29赞 Shahar Shokrani 9/6/2017 #3

检查域的 Web 服务器的配置,这是一项旨在防止 clickJacking 攻击的安全功能,http://www.example.comX-Frame-Options

clickJacking 是如何工作的?

  1. 邪恶的页面看起来与受害者页面完全一样。
  2. 然后它诱骗用户输入他们的用户名和密码。

从技术上讲,邪恶有一个受害者页面的来源。iframe

<html>
    <iframe src='victim-domain.example'/>
    <input id="username" type="text" style="display: none;"/>
    <input id="password" type="text" style="display: none;"/>
    <script>
        //some JS code that click jacking the user username and input from inside the iframe...
    <script/>
<html>

安全功能的工作原理

如果要阻止 Web 服务器请求在 a 中呈现,请添加 x-frame-optionsiframe

X-Frame-Options 拒绝

选项有:

  1. SAMEORIGIN:只允许我自己的域在 iframe 中呈现我的 HTML。
  2. DENY:不允许我的 HTML 在任何 iframe 中呈现
  3. ALLOW-FROM https://example.com/:允许特定域在 iframe 中呈现我的 HTML

这是 IIS 配置示例:

   <httpProtocol>
       <customHeaders>
           <add name="X-Frame-Options" value="SAMEORIGIN" />
       </customHeaders>
   </httpProtocol>

问题的解决方案

如果 Web 服务器激活了安全功能,则可能会导致客户端 SecurityError。

评论

3赞 Noah Gilmore 11/5/2019
我不认为 X-Frame-Options 适用于这里 - 由来宾(嵌入式)页面定义的 X-Frame-Options 可能会导致父级拒绝加载页面,但据我所知,它不会影响 javascript 访问 - 即使使用 X-Frame-Options: *,我认为您将无法使用 javascript 访问不同源来宾页面的 DOM
0赞 rafark 11/23/2021
这个答案实际上并没有回答这个问题,这个问题没有问这是否安全。
19赞 Yakir Manor 12/14/2017 #4

对我来说,我想实现 2 向握手,这意味着:
- 父窗口的加载速度将比 iframe 快 - iframe 应在准备就绪
后立即与父窗口通信 - 父窗口已准备好接收 iframe
消息并重播

此代码用于使用 [CSS 自定义属性]
代码在 iframe 中设置白标:
iframe

$(function() {
    window.onload = function() {
        // create listener
        function receiveMessage(e) {
            document.documentElement.style.setProperty('--header_bg', e.data.wl.header_bg);
            document.documentElement.style.setProperty('--header_text', e.data.wl.header_text);
            document.documentElement.style.setProperty('--button_bg', e.data.wl.button_bg);
            //alert(e.data.data.header_bg);
        }
        window.addEventListener('message', receiveMessage);
        // call parent
        parent.postMessage("GetWhiteLabel","*");
    }
});

父母

$(function() {
    // create listener
    var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
    var eventer = window[eventMethod];
    var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
    eventer(messageEvent, function (e) {
        // replay to child (iframe) 
        document.getElementById('wrapper-iframe').contentWindow.postMessage(
            {
                event_id: 'white_label_message',
                wl: {
                    header_bg: $('#Header').css('background-color'),
                    header_text: $('#Header .HoverMenu a').css('color'),
                    button_bg: $('#Header .HoverMenu a').css('background-color')
                }
            },
            '*'
        );
    }, false);
});

当然,您可以限制来源和文本,这是易于使用的代码
,我发现这个检查很有帮助:
[使用 postMessage 进行跨域消息传递]

评论

0赞 sKopheK 3/22/2018
我正在处理 Safari 的一个问题,即 iframe 中的文档执行其 JS 晚于父页面,这导致消息的发送时间早于 iframe 中的文档侦听消息;这与 Chrome 和 Firefox 的做法完全相反——您是否在 iOS 上的 Safari 中测试过您的代码?顺便说一句,第二个参数值为“*”的 postMessage 不太安全,您应该始终指定域
0赞 Demonic218 2/15/2019
您的第一个代码块是在父级的 iframe 上还是在加载到 iframe 中的页面上?
-65赞 sakthi sudhan 9/22/2018 #5
  • 打开开始菜单
  • 键入 windows+R 或打开“运行”
  • 执行以下命令。

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security

评论

13赞 Quentin 3/26/2019
对于任何不是快速而肮脏的测试来说,这都是可怕的......并且已经在接受的答案中解决了。
5赞 Metafaniel 7/3/2019
即使使用该命令,它也不起作用,因为 Chrome 会避免以这种方式禁用网络安全
0赞 ssp 3/28/2020 #6

我想添加可以对此产生影响的 Java Spring 特定配置。

在网站或网关应用程序中,有一个 contentSecurityPolicy 设置

在 Spring 中,您可以找到 WebSecurityConfigurerAdapter 子类的实现

contentSecurityPolicy("
script-src 'self' [URLDomain]/scripts ; 
style-src 'self' [URLDomain]/styles;
frame-src 'self' [URLDomain]/frameUrl...

...

.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)

如果您没有在此处定义安全的外部连接,浏览器将被阻止。

0赞 Zhanwen Chen 5/22/2020 #7

如果您可以控制 iframe 的内容(也就是说,如果它只是在跨域设置中加载,例如在 Amazon Mechanical Turk 上),则可以使用内部 html 的属性来规避此问题。<body onload='my_func(my_arg)'>

例如,对于内部 html,请使用 html 参数(yes - 已定义,它引用内部 body 元素的父窗口):thisthis

<body onload='changeForm(this)'>

在内部html中:

    function changeForm(window) {
        console.log('inner window loaded: do whatever you want with the inner html');
        window.document.getElementById('mturk_form').style.display = 'none';
    </script>
0赞 Nick K9 6/26/2020 #8

我在尝试嵌入 iframe 然后使用 Brave 打开网站时遇到了此错误。当我将相关站点更改为“Shields Down”时,错误消失了。显然,这不是一个完整的解决方案,因为使用 Brave 访问该网站的任何其他人都会遇到同样的问题。要实际解决它,我需要执行此页面上列出的其他事情之一。但至少我现在知道问题出在哪里了。

3赞 nikk wong 11/20/2021 #9

实际上,对于特定场景,有一种解决方法。

如果有两个进程在同一域上运行,但端口不同,则这两个 Windows 可以不受限制地进行交互。(即 & ).为此,每个窗口都需要将其域更改为共享源:localhost:3000localhost:2000

document.domain = 'localhost'

这也适用于您在同一二级域上使用不同子域的情况,即您正在尝试访问或只是john.site.examplepeter.site.examplesite.example

document.domain = 'site.example'

通过显式设置 ;浏览器将忽略主机名差异,并且 Windows 可以被视为来自“同源”。现在,在父窗口中,您可以访问 iframe:document.domainframe.contentWindow.document.body.classList.add('happyDev')

评论

7赞 user706420 4/13/2022
Chrome 将从版本 106 开始停用修改 document.domain。查看 developer.chrome.com/blog/immutable-document-domain