点击劫持防不胜防?实例讲解并教你如何防御点击劫持攻击
前情提要
如果你了解过点击劫持或者阅读过此篇文章的前传 - 攻击篇,什么是点击劫持?实例讲解并教你如何实施一次点击劫持攻击,即可放心大胆的读下去,因为这是对应防御篇
如果你想来看故事也可以阅读此篇
点击劫持
点击劫持可以绕过我们的 XSS
攻击和 CSRF
攻击防御,属于一种钓鱼网站式的攻击,可以说是防不胜防,攻击者只需要拿到你的网站伪装一下就可以钓鱼成功,对于站主来说和难受,所以必须做点手段防御一下
点击劫持(clickjacking)是一种在网页中将恶意代码等隐藏在看似无害的内容(如按钮)之下,并诱使用户点击的手段。 该术语最早由雷米亚·格罗斯曼(Jeremiah Grossman)与罗伯特·汉森(Robert Hansen)于2008年提出。 这种行为又被称为界面伪装(UI redressing)。 - 维基
原理
详细原理请观看本篇文章的前传,本篇文章主要防御的其中的经典点击劫持,用四张图就很好理解
就是 follow.html
里的敏感操作,比如关注按钮,暴露在钓鱼网站 clickjacking.html
,诱导用户点击这个关注按钮,从而到达攻击目的(获得关注),如下
- 充满诱惑性的钓鱼网站
- 实际上这个按钮的最顶层(
CSS
层面),隐藏了一个iframe
- 这个被攻击网站,有一部分和钓鱼网站重叠,一旦用户点击了钓鱼网站和被攻击网站的重叠部分,就会被夺取一个关注(被攻击了)
- 被攻击网站原视角
防御
关于防御的所有源代码可以在线查看
X-Frame-Options
X-Frame-Options
是 HTTP Header
的一个字段,一个请求头字段
它有以下三个值
DENY
- 始终禁止在 frame 中显示此页面。SAMEORIGIN
- 允许在和父文档同源的 frame 中显示此页面。ALLOW-FROM domain
- 允许在来自给定域的父文档的 frame 中显示此页面。
由于项目使用的是 express.static
来做的静态服务器,因此可以使用以下方式添加请求头
app.use(express.static(path.join(__dirname, "public")), {
setHeaders: function (res, path, stat) {
if (res) {
res.setHeader("X-Frame-Options", "DENY");
}
},
});
效果如下,立竿见影
这时候取消钓鱼网站里 iframe
的 opacity: 0
就可以看到,浏览器会拒绝访问网站
此时响应头中设置了 X-Frame-Options
为 DENY
X-Frame-Options
的其它值效果也是一致的,可以根据自己网站的需要去添加(万一自己的某些网站真的需要 iframe
引用自己的其它网站呢?)
express.static 的请求头设置我一顿好找,还好 google 一位 express 源码哥给到了答案
遮罩层
通过在具有敏感操作的界面设置一个遮罩在捕获阶段阻挡所有的点击事件(或者有可能触发点击劫持的所有事件)
这个就需要了解一下 DOM
的事件传播的三个阶段
- 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
- 目标阶段(Target phase)—— 事件到达目标元素。
- 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡。
既然点击劫持是利用了被害网站的点击事件,那么在知道是 iframe
的情况下,去决定是否要将点击传递给目标 DOM
(也就是被攻击的敏感操作,比如关注按钮)
实现如下
关于实现捕获阶段拦截事件的具体原理和 API 解析,请查阅文档
<body>
<div class="protector">
fans: <span class="fansTotal"></span>
<button class="follow" onclick="handleFollowClick()">Follow</button>
</div>
</body>
<script>
const protector = document.querySelector(".protector");
protector.addEventListener(
"click",
(event) => {
console.log("阻止点击事件传播");
event.stopPropagation();
},
true
);
// 业务代码
// ...
const handleFollowClick = () => {
const xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:3000/user/follow");
// ...
};
</script>
follow.html
效果如下,加上遮罩后,不会再向后端发送关注的 Ajax
请求
钓鱼网站效果如下
总结
有点标题党了,其实点击劫持并没有很多,因为点击劫持需要诱导用户去和钓鱼网站产生交互行为,因此这种攻击比较少见
参考资料
转载自:https://juejin.cn/post/7182971571672186938