是否有检测 X-Frame-Options 的客户端方法?
Posted
技术标签:
【中文标题】是否有检测 X-Frame-Options 的客户端方法?【英文标题】:Is there a client-side way to detect X-Frame-Options? 【发布时间】:2011-12-18 12:12:26 【问题描述】:有什么好的方法可以检测页面何时因为 X-Frame-Options 标头而不会显示在框架中?我知道我可以请求页面服务器端并查找标头,但我很好奇浏览器是否有任何机制来捕获此错误。
【问题讨论】:
据我所知,经过一些研究,目前无法从客户端找到它。我尝试使用“受保护”的 URL 加载 iFrame src,用 try/catch 包装它,但它不起作用。如果您碰巧找到解决方案,请分享。谢谢。 我为此创建了一个 Webkit 错误。 bugs.webkit.org/show_bug.cgi?id=90660 以下所有答案都是错误的!由于Same-origin
政策,您不能使用 XHR 请求和读取标头。您不能使用frame.contentWindow
或frame.contentDocument
,在许多情况下它们为空。我不知道解决方案是什么,但我测试了下面的所有答案,但没有一个有效。
【参考方案1】:
好的,这个很旧,但仍然很重要。
事实: 当 iframe 加载被 X-Frame-Options 阻止的 url 时,加载时间非常短。
破解: 因此,如果 onload 立即发生,我知道它可能是 X-Frame-Options 问题。
免责声明: 这可能是我编写的“最骇人听闻”的代码之一,所以不要期望太多:
var timepast=false;
var iframe = document.createElement("iframe");
iframe.style.cssText = "position:fixed; top:0px; left:0px; bottom:0px; right:0px; width:100%; height:100%; border:none; margin:0; padding:0; overflow:hidden; z-index:999999;";
iframe.src = "http://pix.do"; // This will work
//iframe.src = "http://google.com"; // This won't work
iframe.id = "theFrame";
// If more then 500ms past that means a page is loading inside the iFrame
setTimeout(function()
timepast = true;
,500);
if (iframe.attachEvent)
iframe.attachEvent("onload", function()
if(timepast)
console.log("It's PROBABLY OK");
else
console.log("It's PROBABLY NOT OK");
);
else
iframe.onload = function()
if(timepast)
console.log("It's PROBABLY OK");
else
console.log("It's PROBABLY NOT OK");
;
document.body.appendChild(iframe);
【讨论】:
如果客户端的连接开始时延迟很差,则非常不可靠。 这里要提的一大堆东西。是的,它不可靠,因为速度(即 500 毫秒,可能是 1000 毫秒还是 200 万毫秒?)这取决于连接速度。为此,您可能需要做一些技巧:例如,预加载 DNS。或者点击一个单独的页面,跟踪加载所需的时间,然后根据该时间,将 500 毫秒设置为 1 小时或 100 毫秒。这取决于。接下来,如果页面没有加载,你仍然不知道是不是因为 X-Frame-Options 标头。您只知道它没有加载,这可能就是您需要知道的全部内容。【参考方案2】:免责声明:我在 2012 年写的这个答案(当时 Chrome 的版本约为 20)已经过时,我将其保留在这里仅用于历史目的。阅读和使用风险自负。
好的,这是一个有点老的问题,但这是我发现的(这不是一个完整的答案)Chrome/Chromium。
检测指向外部地址的框架是否已加载的方法只是尝试访问其 contentWindow 或文档。
这是我使用的代码:
element.innerhtml = '<iframe class="innerPopupIframe" src="'+href+'"></iframe>';
myframe = $(element).find('iframe');
然后,稍后:
try
var letstrythis = myframe.contentWindow;
catch(ex)
alert('the frame has surely started loading');
事实是,如果 X-Frame-Options 禁止访问,那么 myFrame.contentWindow
将可以访问。
这里的问题是我所说的“然后,稍后”。我还没有弄清楚要依赖什么,订阅哪个事件来查找何时是执行测试的好时机。
【讨论】:
这不再有效。访问 contentWindow 不会引发异常。【参考方案3】:这是基于@Iftach 的回答,但不那么老套。
它检查 iframe.contentWindow.length > 0
是否表明 iframe 已成功加载。
此外,它还会检查 iframe onload
事件是否在 5 秒内触发并发出警报。这会捕获混合内容的失败加载(尽管以一种骇人听闻的方式)。
var iframeLoaded = false;
var iframe = document.createElement('iframe');
// ***** SWAP THE `iframe.src` VALUE BELOW FOR DIFFERENT RESULTS ***** //
// iframe.src = "https://davidsimpson.me"; // This will work
iframe.src = "https://google.com"; // This won't work
iframe.id = 'theFrame';
iframe.style.cssText = 'position:fixed; top:40px; left:10px; bottom:10px;'
+ 'right:10px; width:100%; height:100%; border:none; margin:0; padding:0; overflow:hidden; z-index:999999;';
var iframeOnloadEvent = function ()
iframeLoaded = true;
var consoleDiv = document.getElementById('console');
if (iframe.contentWindow.length > 0)
consoleDiv.innerHTML = '✔ Content window loaded: ' + iframe.src;
consoleDiv.style.cssText = 'color: green;'
else
consoleDiv.innerHTML = '✘ Content window failed to load: ' + iframe.src;
consoleDiv.style.cssText = 'color: red;'
if (iframe.attachEvent)
iframe.attachEvent('onload', iframeOnloadEvent);
else
iframe.onload = iframeOnloadEvent;
document.body.appendChild(iframe);
// iframe.onload event doesn't trigger in firefox if loading mixed content (http iframe in https parent) and it is blocked.
setTimeout(function ()
if (iframeLoaded === false)
console.error('%c✘ iframe failed to load within 5s', 'font-size: 2em;');
consoleDiv.innerHTML = '✘ iframe failed to load within 5s: ' + iframe.src;
consoleDiv.style.cssText = 'color: red;'
, 5000);
在这里进行现场演示 - https://jsfiddle.net/dvdsmpsn/7qusz4q3/ - 这样您就可以在相关浏览器中对其进行测试。
在撰写本文时,它适用于 Chrome、Safari、Opera、Firefox、Vivaldi 和 Internet Explorer 11 上的当前版本。我尚未在其他浏览器中测试过它。
【讨论】:
我将该小提琴中的 src 更改为 iframeable 的“basicinstructions.net”,但它仍然会在 5 秒后出现错误加载。也许是因为我没有超高速互联网? 为什么?它是 iframeable,没有 X-Frame-Options。 由于 jsfiddle 在 https 上是安全的,因此 http 上的 iframe 通常会被浏览器阻止。这就是我在 5s 测试后添加 onload 的原因。请注意,我测试的两个 URL 都只是 https。 有点晚了,但我也遇到了这个问题,即使页面加载到 iframe 中,使用fr.wikipedia.org/wiki/Main_Page 进行测试也不起作用。 经过数小时的搜索终于解决了我的问题!【参考方案4】:我唯一能想到的就是为url代理一个AJAX请求,然后查看标头,如果没有X-Frame-Options,则在iframe中显示。远非理想,但总比没有好。
【讨论】:
不幸的是,跨域问题将阻止此工作。除非您当然可以找到或使自己成为复制标题的代理。 是的,你完全正确;我的愚蠢疏忽。我更新了我的答案。感谢您指出这一点! 这可能是最接近答案的事情,尽管不知道代理位置是否被该服务阻止,或者用户是否可能登录到该站点,在这种情况下他们无法发送该标头.这也可能会使所有在加载之前以这种方式检查的请求,因为它是由代理请求的,所以速度要慢两倍。【参考方案5】:至少在 Chrome 中,您会注意到加载失败,因为 iframe.onload 事件没有触发。您可以将其用作页面可能不允许 iframe 的指示。
【讨论】:
Chrome 现在确实会触发它。【参考方案6】:在线测试工具可能很有用。 我用https://www.hurl.it/。 您可以清楚地看到响应标头。 寻找 X 框架选项。如果值为拒绝 - 它不会显示在 iframe 中。 同源——仅来自同一个域, allow- 将允许来自特定网站。
如果您想尝试其他工具,您可以简单地在 Google 上搜索“http request test online”。
【讨论】:
【参考方案7】:这可以通过
来实现a) 通过 CreateElement 创建一个新的 IFrame
b) 将其显示设置为“无”
c) 通过 src 属性加载 URL
d) 为了等待 iframe 加载,请使用 SetTimeOut 方法延迟函数调用(我已将调用延迟了 10 秒)
e) 在该函数中,检查 ContentWindow 长度。
f) 如果长度 > 0,则加载 url,否则由于 X-Frame-Options 不加载 URL
下面是示例代码:
function isLoaded(val)
var elemId = document.getElementById('ctlx');
if (elemId != null)
document.body.removeChild(elemId);
var obj= document.createElement('iframe');
obj.setAttribute("id", "ctlx");
obj.src = val;
obj.style.display = 'none';
document.body.appendChild(obj);
setTimeout(canLoad, 10000);
function canLoad()
//var elemId = document.getElementById('ctl100');
var elemId = document.getElementById('ctlx');
if (elemId.contentWindow.length > 0)
elemId.style.display = 'inline';
else
elemId.src = '';
elemId.style.display = 'none';
alert('not supported');
【讨论】:
【参考方案8】:这就是我检查 X-Frames-Options 以满足我的要求之一的方式。在加载 JSP 页面时,您可以使用 AJAX 向特定 URL 发送异步请求,如下所示:
var request = new XMLHttpRequest();
request.open('GET', <insert_URL_here>, false);
request.send(null);
完成后,可以读取收到的响应头如下:
var headers = request.getAllResponseHeaders();
然后您可以对其进行迭代以找出 X-Frames-Options 的值。一旦有了值,就可以在适当的逻辑中使用它。
【讨论】:
同源策略会阻止您请求任意 URL。除非 Access-Control-Allow-Origin: * 是一个不太可能的标题。 我对此表示怀疑。我记得曾将它用于我应该在我的项目中修复的错误之一。该错误涉及打开外部链接。所以我们必须以某种方式确定链接是否可以在 iframe 中打开(如果不能,我们必须在新选项卡中打开它)。这与我所做的类似,截至目前,它仍然是一个可以接受的解决方案。当然,项目特定的东西可能会出现。 确实它不起作用给任何任意网站 url:Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://www.openstreetmap.org/. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
以上是关于是否有检测 X-Frame-Options 的客户端方法?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 express.js node.js 中设置 X-Frame-Options
Content-Security-Policy 如何与 X-Frame-Options 一起使用?