背景
项目中部署了General 和 Elastic kabana来监控服务器性能,因为部署在不同的服务器,每次查看时需要打开不同的系统,非常麻烦,所以将他们内嵌到中心系统里方便查看。
实现方式
前端使用vue3,通过路由meta获取iframe加载的url。
const frameSrc = ref<string>("");
if (unref(currentRoute.meta)?.frameSrc) {
frameSrc.value = unref(currentRoute.meta)?.frameSrc as string;
}
<iframe :src="frameSrc" class="frame-iframe" ref="frameRef" />
问题1:通过iframe嵌入后,页面无法正常加载
控制台报错Refused to display 'http://xxx.xxx.xxx.xxx:8008/' in a frame because it set 'X-Frame-0ptions' to 'deny'
原因:
当目标网站设置了X-Frame-Options
为DENY
或SAMEORIGIN
时,会导致目标网址无法被通过iframe加载。
解决方案:
将目标网址的X-Frame-0ptions
设置为 ALLOW-FROM uri
:表示页面只能被指定uri的iframe嵌入。
问题2:Elastic目标页面可正常加载,但无法登录
查看Elastic kabana官方文档 需将xpack.security.sameSiteCookies
设置为none
Cookie SameSite
标记:
SameSite:默认情况下,浏览器要求跨站点的第三方Cookie具有SameSite属性设置(通常为Lax或Strict)。如果子系统返回的Cookie没有设置SameSite属性,或者设置为None并且没有Secure标记,浏览器也会拒绝接受该Cookie。
但这简单的操作之后并无法正常访问,继续排查。
Cookie Secure
标记:
Secure标记是指当浏览器向服务器发送请求时,只有使用HTTPS协议的连接才会传递该Cookie。如果服务器返回的Set-Cookie头部没有包含Secure标记,浏览器就会拒绝接收该Cookie,并将其视为不安全的Cookie。
SameSite=none 只支持HTTPS接口。如果要设置该值,需要在对应的Cookie上同时设置Secure属性
解决方案:
将目标地址访问方式升级为https,并添加Secure标记
问题3:获取iframe页面中的dom元素失败
因嵌入的第三方系统与父系统是完全不一样的用户体系,并且没必要做统一认证,所以想要在iframe中直接获取到用户名密码输入框模拟自动登录,但在控制台中报错。
获取方式:
const frameRef = ref<HTMLElement | null>(null);
const iframe = unref(frameRef);
const usernameInput =iframe.contentWindow.document.getElementsByClassName("username");
console.log(usernameInput);
<template>
<iframe :src="frameSrc" class="frame-iframe" ref="frameRef" />
</template>
错误信息:
Uncaught DOMException: Blocked a frame with origin "http://localhost:8848" from accessing a cross-origin frame
原因:出现这个错误的原因是因为存在跨域安全限制,阻止了不同源的页面访问另一个页面。这是出于安全和隐私的考虑所制定的策略。
解决方案:
- 若可修改第三方系统,可改造第三方系统,通过子系统调用 postMessage Api实现向父页面通讯
- 将第三方系统与父系统部署到同域下,可实现在父页面操作iframe中的内容
小结
通过iframe嵌入第三方系统时,通常第三方系统为了保障系统安全,一般会禁止被嵌入,可以在保证安全的情况下,修改目标地址的被访问策略来实现
- X-Frame-Options限制
- 站点会话和Cookie策略
- 跨域资源共享(CORS)限制
- 跨域限制、Secure标记和SameSite属性