防范点击劫持必须使用服务端http响应头content-security-policy的frame-ancestors指令,禁用所有前端js方案;旧浏览器可兜底添加x-frame-options,但不可单独依赖。
防范点击劫持,关键不在于干预事件冒泡路径——因为篡改event.stoppropagation()或重写dispatchevent等前端js手段对点击劫持完全无效。攻击发生在浏览器解析html前的帧加载阶段,js执行时早已错过防御窗口。真正起效的只有服务端主动声明的响应头策略。
必须用HTTP响应头,不能靠前端代码
以下方式全部无效,应立即停用:
- meta标签设置X-Frame-Options:所有现代浏览器无视,规范从未支持
- JS检测top !== self后跳转或遮罩:可被sandbox iframe绕过,且页面已渲染、按钮可点击
- 监听click事件并阻止冒泡/取消默认行为:攻击者覆盖层在iframe内触发原生点击,不经过宿主页面JS上下文
优先配置Content-Security-Policy frame-ancestors
这是W3C现行标准,Chrome/Firefox/Edge自2020年起以它为准,X-Frame-Options会被静默忽略。配置示例:
-
禁止所有嵌入:
Content-Security-Policy: frame-ancestors 'none' -
仅允许同源:
Content-Security-Policy: frame-ancestors 'self'(注意不支持路径如'self'/admin) -
允许多个可信域名:
Content-Security-Policy: frame-ancestors https://embed.example.com https://dashboard.company.net(allow-from早已失效,此方式是唯一替代)
旧浏览器兜底:谨慎保留X-Frame-Options
仅当需兼容IE10/11或老版Safari时添加,且必须与CSP配合,不可单独依赖:
- 同时发送
X-Frame-Options: DENY和Content-Security-Policy: frame-ancestors 'none',顺序无关 - 避免混用语义重复配置,例如
frame-ancestors 'self'+X-Frame-Options: SAMEORIGIN - 若使用Spring Security、Django或ThinkPHP等框架,先关闭其自动注入的X-Frame-Options,再统一由CSP控制,防止冲突
ThinkPHP等PHP框架实操要点
在ThinkPHP 6/7中,应在全局中间件统一注入,确保JSON接口、错误页、文件下载等所有响应都生效:
- 在
app/middleware.php中注册闭包中间件:function($request, \Closure $next) {<br> $response = $next($request);<br> return $response->header('Content-Security-Policy', "frame-ancestors 'none'");<br>} - 禁用框架自带X-Frame-Options(如ThinkPHP的
think\middleware\TrustHost可能注入),避免双头冲突 - 不推荐在控制器里逐个调用
header(),极易遗漏且无法覆盖异步任务、CLI等场景











