Vue嵌套路由页面如何防御Strokejacking攻击?
我在开发一个Vue项目时,用户页面需要嵌入第三方的表单页面。最近测试时发现,攻击者可能通过iframe嵌套我们的表单页,用透明层覆盖实现Strokejacking。尝试在后端设置X-Frame-Options: DENY,但发现嵌入的页面仍然能被加载,这到底是哪里出错了?
尝试过以下方法:
1. 在Nginx配置加了add_header X-Frame-Options SAMEORIGIN;
2. Vue组件里动态设置allow attribute:
mounted() {
this.$el.setAttribute('allow', 'prevent-frame-navigation');
}
但iframe仍然能显示页面,该怎么彻底阻止跨域嵌套呢?
先说重点:你在 Nginx 加了 add_header,但这个指令在 Nginx 的子请求或者某些条件下是不会生效的,尤其是当有 location 匹配冲突、或者被 proxy_pass 覆盖的时候。你要确保这个 header 是从你真正返回 HTML 的那个服务端出口发出来的,比如后端接口或静态资源服务。
你可以打开浏览器开发者工具,Network 里找你的页面 HTML 响应,看 Response Headers 有没有 X-Frame-Options。如果没有,那就说明配置白加了。
另外,X-Frame-Options 只支持三个值:DENY、SAMEORIGIN、ALLOW-FROM(但 ALLOW-FROM 兼容性极差,基本不能用)。所以如果你是想完全禁止嵌套,必须确保所有环境都返回 X-Frame-Options: DENY,并且这个 header 是直接由服务端返回 HTML 时带上的。
Vue 组件里 setAttribute('allow', 'prevent-frame-navigation') 这种写法是无效的,allow 属性是用在 iframe 标签上的,不是给根元素随便设的,这完全不起作用。
正确的防御方式就两条:
1. 确保服务端(Nginx 或后端)对页面的 HTML 响应返回
X-Frame-Options: DENY,并且在所有环境下都能看到这个 header。2. 同时加上
Content-Security-Policy: frame-ancestors 'none';,这是现代浏览器推荐的方式,比 X-Frame-Options 更强更灵活。如果是只允许同域,就设为frame-ancestors 'self';比如 Nginx 配置:
最后提醒一点:如果第三方表单页是你自己控制的域名,那也要在那个服务上同样设置;如果是别人家的页面,那你根本防不住他们嵌你,只能保证自己不被别人嵌。Strokejacking 主要靠防止被嵌套来解决,别指望前端 JS 能搞定这事。
检查下你现在线上页面的响应头,八成是根本没返回这些安全头,光代码里折腾没用。
首先,Nginx的
add_header X-Frame-Options SAMEORIGIN;是没错的,但它只对同源生效。如果你的页面被跨域嵌套了,还需要在前端加一道防线。直接在Vue组件里写个简单的判断:这段代码的作用是:如果当前页面被iframe嵌套了(也就是
window.top不是自己),就强制跳转到顶层窗口。这种方法简单粗暴,兼容性也很好。另外,你说的那个
allow属性其实是个新玩意儿,主要是针对某些特定的安全策略,但对付 Strokejacking 还是上面那段代码更靠谱。最后提醒一下,后端的X-Frame-Options还是要保留,前后端结合才能更稳妥。如果项目有CSP(内容安全策略),也可以加上
frame-ancestors 'self';,双重保险总是好的。