如何在Safari 15-16.3中实现仅允许iframe嵌入访问网页的限制?
针对Safari 15-16.3的替代实现方案
要实现阻止直接URL访问、允许iframe嵌入的需求,在不支持Sec-Fetch-Site的Safari版本中,可以通过服务器端Referer头校验结合前端上下文检查的方式实现,双重保障可靠性:
1. 服务器端(Next.js)校验Referer头
直接访问时,Referer请求头通常为空(或仅包含当前站点域名);而页面被iframe嵌入时,Referer会携带父页面的域名信息。你可以在Next.js的中间件或页面的getServerSideProps中添加以下逻辑:
// 示例:Next.js 中间件 middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export function middleware(request: NextRequest) { const referer = request.headers.get('referer'); const currentHost = request.headers.get('host'); // 无Referer大概率是直接访问,拦截 if (!referer) { return NextResponse.redirect(new URL('/blocked', request.url)); } const refererHost = new URL(referer).host; // 跨域Referer说明是跨域iframe嵌入,允许访问 if (refererHost !== currentHost) { return NextResponse.next(); } // 同域来源,可能是同域跳转或同域iframe,允许请求但交由前端进一步验证 return NextResponse.next(); } // 指定需要拦截的页面路径 export const config = { matcher: '/your-protected-page/:path*', };
2. 前端页面上下文检查
对于同域嵌入或服务器端无法准确判断的场景,在页面加载时通过JS检查当前页面是否处于iframe中:
// 在受保护的页面组件中添加 import { useEffect } from 'react'; export default function ProtectedPage() { useEffect(() => { if (window.top === window.self) { // 不在iframe中,判定为直接访问,跳转至拦截页面 window.location.href = '/blocked'; } }, []); return <div>仅允许iframe嵌入访问的内容</div>; }
这种方式可以覆盖同域iframe嵌入的场景,同时补充服务器端校验的不足(服务器端无法区分同域跳转和同域iframe)。
注意事项
Referer头可能在隐私模式下被浏览器隐藏,此时服务器端会误判为直接访问,前端检查可作为兜底方案。- 前端检查可被禁用JS绕过,但结合服务器端校验能覆盖绝大多数正常场景。
- 若仅允许特定域名的iframe嵌入,可在服务器端进一步校验
Referer的域名是否在白名单内,提升安全性。
内容的提问来源于stack exchange,提问作者Ivan Banha
相关产品推荐
相关产品推荐

