SecurityError:阻止一个原始帧访问一个跨原始帧

我正在我的超文本标记语言页面中加载<iframe>并尝试使用JavaScript访问其中的元素,但当我尝试执行我的代码时,我收到以下错误:

阻止原始“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!";
});
});
1464206 次浏览

同源规则

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

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

protocol://hostname:port/...

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

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

Examples

Here's what would happen trying to access the following URLs from 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

解决方法

即使主域同源策略阻止脚本访问具有不同来源的站点的内容,如果您拥有这两个页面,则可以使用#EYZ0及其相对的message事件来解决此问题也可以在两个页面之间发送消息,如下所示:

  • 在您的主页上:

    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()),没有任何区别。

浏览器中禁用主域同源策略

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

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

检查域的Web服务器是否有X-Frame-Optionshttp://www.example.com配置 它是一个安全功能,旨在防止点击劫持攻击,

点击劫持如何工作?

  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>

安全功能如何工作

如果要防止在iframe中呈现Web服务器请求,请添加x帧选项

X帧选项DENY

这些选择是:

  1. SAMEORIGIN:只允许我自己的域在iFrame中呈现我的超文本标记语言。
  2. DENY:不允许我的超文本标记语言在任何iFrame中呈现
  3. ALLOW-FROM https://example.com/:允许特定域在iFrame中呈现我的超文本标记语言

这是IIS配置示例:

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

问题的答案

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

对我来说,我想实现一个双向握手,意思是:
-父窗口的加载速度比ifram
快 -ifram应该在准备就绪后立即与父窗口对话
-父级已准备好接收ifram消息并重放

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

$(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进行跨域消息传递]

  • 打开开始菜单
  • 键入windows+R或打开”运行
  • 执行以下命令。

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

我想添加JavaSpring特定配置,可以对此产生影响。

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

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

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

.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)

如果您未在此处定义安全外部内容集,浏览器将被阻止。

如果您可以控制ifram的内容——也就是说,如果它只是在亚马逊土耳其机器人等跨源设置中加载——您可以使用内部html的<body onload='my_func(my_arg)'>属性来规避这个问题。

例如,对于内部html,使用this html参数(是的-this已定义,它指的是内部body元素的父窗口):

<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>

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

实际上,对于特定场景,有一个变通方法。

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

document.domain = 'localhost'

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

document.domain = 'site.example'

通过明确设置document.domain;,浏览器将忽略主机名差异,并且Windows可以被视为来自“同源”。现在,在父窗口中,您可以进入ifram:frame.contentWindow.document.body.classList.add('happyDev')