React 项目如何防止被嵌入 iframe 导致点击劫持?
我最近在做公司后台系统,用的是 React,担心被人用 iframe 嵌套我们的页面搞点击劫持。听说可以通过设置 X-Frame-Options 或 Content-Security-Policy 来防护,但我在前端代码里加了好像没生效?
我在 App.js 里尝试用 useEffect 加了个 meta 标签,但控制台报错说无效,而且页面还是能被别人用 iframe 嵌入。是不是这种防护只能在后端设置?前端能做点啥吗?
useEffect(() => {
const meta = document.createElement('meta');
meta.httpEquiv = 'Content-Security-Policy';
meta.content = "frame-ancestors 'self'";
document.head.appendChild(meta);
return () => document.head.removeChild(meta);
}, []);
先说为什么你的代码不生效:X-Frame-Options 和 Content-Security-Policy 这些都是 HTTP 响应头,是在服务器返回响应时就决定好的。浏览器收到响应后才会解析 meta 标签,但 CSP 的 frame-ancestors 这类指令根本不支持通过 meta 标签设置,浏览器直接忽略。所以你动态添加 meta 标签完全是白忙活。
真正的解决办法还是在后端。服务端配置就几种方式:
Nginx 的话在 server 块加
add_header X-Frame-Options "SAMEORIGIN";,或者用 CSP 的话add_header Content-Security-Policy "frame-ancestors 'self'";。Apache 用 .htaccess 设置Header set X-Frame-Options "SAMEORIGOR"。如果你用云服务比如阿里云 CDN,也可以在 CDN 配置里加这些响应头。如果你实在控制不了后端,前端倒是能做个检测然后强行跳转,代码大概这样:
不过这种方式只能防止普通用户点击劫持,稍微懂点技术的直接就能禁掉你的 JS 绕过这个检测。所以后端配置才是靠谱的方案,前端这个也就是个辅助手段。
你们公司后端是 nginx 的话让运维加一行配置就完事了,比在前端折腾省事多了。
我之前踩过这个坑,后来搞清楚了:
后端设置是必须的。X-Frame-Options 和 CSP 的 frame-ancestors 都得在服务器响应时加上响应头,前端改不了。所以你们后端配置 nginx 或者后端代码里一定要加:
nginx 的话:
add_header X-Frame-Options "SAMEORIGIN";
add_header Content-Security-Policy "frame-ancestors 'self'";
后端语言的话也都有对应的方式设置响应头。
前端能做的事:虽然不能彻底解决,但可以加个检测脚本,被嵌入时给用户提个醒,或者直接跳转到顶级窗口。我之前项目里这么干的:
不过得说句实话,这种前端方案防君子防不住小人,技术流可以直接把这个检测代码给你干失效。真正的防护还是得靠后端设置响应头,前端这个算是个双保险和用户体验层面的保护。