原文:https://webcache.googleusercontent.com/search?q=cache:kv9fSsl32yEJ:https://blog.innerht.ml/google-yolo/+&cd=1&hl=en&ct=clnk

在当今世界中,按钮已经无处不在,如电梯按钮、机械按钮,甚至位于总统办公桌上的“核按钮”,等等。但是,你是否想过,当我们按下这些按钮时,它们所执行的真的是我们想要的操作吗?

<iframe>是一个HTML元素,可用于在一个网页中嵌入另一个网页。在下面的页面中,我嵌入了一个伪造的银行网站(这个例子是从@lcamtuf那里学来的,并做了稍微的改动)页面。

注意:这里仅仅给出示意图,实际效果请访问原文

就本场景来说,您只要点击了“Transfer everything”按钮,那么您的所有资金应该会全部转给我。当然这里只是给出一个场景,实际上,点击后并不会发生任何事情。但是,您会点击它吗?

现在,我们为读者介绍另一个按钮。除了提示“无害性”之外,该按钮没有给出任何信息,不过,我建议您点击试试。

注意:这里仅仅给出示意图,实际效果请访问原文

呃哦,看起来你的钱都归我了。别担心,这只是虚拟货币,根本不值钱(这一点与比特币截然相反)。那么,究竟是怎么回事呢?我们知道,CSS有一个名为position的属性,可用于将一个元素放到另一个元素的上面。另外,属性pointer-events还允许点击事件“穿过”一个元素,这样的话,用户的点击实际上将注册到下面的元素上。当将两者结合使用时,攻击者就可以在实际按钮上叠加一个假按钮,并诱骗受害者点击它。读者可以通过“Behind the scene”按钮来直观地了解其工作机制。这是一种经常被忽视和误解的Web应用程序漏洞,通常称为Clickjacking,或点击劫持漏洞。

预期的应用场景

由此可见,<iframe>是非常危险的,pointer-events更是致命的,那么,我们是否应该删除它们呢?也是,也不是。如果没有应用场景,许多东西就根本不会被发明出来,<iframe>也是如此。事实上,在线广告是严重依赖于<iframe>的。更重要的是,web widget也需要用到<iframe>。此外,Facebook的like按钮和Facebook评论插件也是利用<iframe>实现的。

下面是另一个无害的按钮,我建议读者单击一下,试试会发生什么。

注意:这里仅仅给出示意图,实际效果请访问原文

如果您已经登录Facebook,那么您刚才的点击动作,实际上是去给我的贴子点赞(在此谢过),不过这一点您自己根本意识不到。这一次,我们利用的是opacity属性,而非pointer-events。实际上,opacity是用于控制元素不透明度的一个CSS属性。当然,攻击者只要将透明的Facebook like 按钮堆叠到其他可见的按钮的上面,也可以实现相同的点击劫持效果,因此,即使不用pointer-events,照样会受到点击劫持攻击的威胁。顺便说一下,这其实是一种名为Likejacking的Blackhat SEO技术,本质上就是利用点击劫持攻击来获得大量有效的赞。

注意:这里仅仅给出示意图,实际效果请访问原文

算起来,攻击者通过 web widget来利用点击劫持漏洞已经有一段日子了。实际上,许多社交媒体网站都很容易受到这种威胁的影响。例如,攻击者可以通过点击劫持攻击,利用Twitter的关注按钮来“吸粉”,或者利用LinkedIn的自动填充按钮将访问者的信息泄露给第三方网站。现在,这些网站已开始通过添加用户交互来修复这些问题,例如,为用户打开一个新窗口来确认操作等。事实上,Likejacking现在可能已经失效了。如果点击上面的Facebook like按钮,它可能会变成“Confirm”按钮,也就是要求您再次点击以进行确认。实质上,他们现在使用算法来判断嵌入的网站是否值得信赖,从而确定额外的用户交互数量,以在可用性和安全性之间的取得平衡。

Framebuster


显然,“消灭”<iframe>和某些CSS属性并不是一个好主意。我们真正需要的,是让网站获得禁止其他网站嵌入其中的能力。之前,人们开发了一种名为Framebusting的技术,该技术可以使用JavaScript来检查一个网站是否嵌入了其他网站的页面。由于window.top总是指向最外层的框架,因此,通过将它与window.self进行比较,就可以确定嵌入的站点是否为其自身。下面给出一段最常用的JavaScript检测代码:

if (top != self)
  top.location = self.location

但是,基于JavaScript的framebuster通常都有许多安全缺陷。例如,onBeforeUnload可以中止导航;XSS Filter可以禁止执行特定的JavaScript代码,这一点我在之前的一篇文章中已经介绍过了;同时,<iframe>的sandbox属性甚至可以全面禁止嵌入的站点中的所有JavaScript代码。此外,论文《 Busting Frame Busting: a Study of Clickjacking Vulnerabilities on Popular Sites》的研究结果进一步表明,基于JavaScript的framebuster在安全方面确实是非常脆弱的。

幸运的是,各浏览器已经开始支持HTTP响应头X-Frame-Options,用来控制自己网站的页面是否可以嵌入到iframe或frame中:X-Frame-Options:DENY表示自己网站页面不能被嵌入到任何iframe或frame中;X-Frame-Options:SAMEORIGIN表示页面只能被本站页面嵌入到iframe或者frame中;X-Frame-Options:ALLOW-FROM表示只有指定的站点才能将本站页面嵌入到iframe或者frame中。注意: CSP Level 2 规范中的 frame-ancestors 指令会替代这个非标准的头部。

但是,X-Frame-Options:SAMEORIGIN存在一个严重的安全漏洞:只将嵌入的网站与顶层的frame进行比较

有的读者可能会问,既然嵌入的页面与顶层的frame是同源的,为什么还会出问题呢? 别忘了,一些网站或明或暗地允许使用自定义iframe。实际上,Twitter Player Card就很容易受到这个安全隐患的影响。当你推送链接时,Twitter将获取链接并读取其meta数据。如果Open Graph属性指定了播放器的URL,则Twitter会将该URL直接嵌入到时间轴中的iframe中。这样,我们就可以在“播放器”中嵌入一个敏感的Twitter页面,例如OAuth授权页面,然后在授权按钮上面覆盖一个假按钮。

注意:这里仅仅给出示意图,实际效果请访问原文

在实际的漏洞利用中,我在主窗口中通过onblur来检测点击事件,因为只要点击iframe就会触发相应的焦点事件,然后,我会发送一个反馈(播放视频),使点击劫持不那么显而易见。如果读者感兴趣的话,可以从我的演示文档中了解更多的相关示例。

在撰写本文时,只有Chrome和Firefox通过对所有frame祖先进行检查修复了这个安全问题,这里的frame祖先与CSP的frame-ancestors 'self'是相一致的。

回到正题上来……


我知道您在想什么:上面说了这么多,但是到底跟“Google YOLO”有什么关系呢?在告诉您答案之前,建议读者先登录Google并刷新该页面:),如果您是在PC上通过现代浏览器来浏览该页面的话,将会收获一份“惊喜”:)

YOLO(You Only Login Once,您只需登录一次)是谷歌提供的一种web widget:用户只需在应用程序或网站上登陆一次,并保存到智能密码锁中,密码将经由此智能程序自动登录到各个设备上。返厂重置手机和加载新手机都变得更加简单,因为一旦登录谷歌账户,所有认证信息将自动应用到客户的所有设备中,无需登录第二次。也就是说,我们在自己的网站上嵌入了Google提供的iframe,用户只需通过一次简单的点击即可通过Google帐户进行身份验证。具有讽刺意味的是,“web widgets”和“one click”确实是YOLO(You Only Live Once,你只活一次)。

还记得之前点击的cookie同意按钮吗?是的,这是一个点击劫持攻击:)。

当您使用Google YOLO登录时,会传输以下数据:

{
  "id": "filedescriptor@gmail.com",
  "authMethod": "https://accounts.google.com",
  "authDomain": "https://blog.innerht.ml",
  "displayName": "file descriptor",
  "profilePicture": "https://lh6.googleusercontent.com/-enDr8I8LBzQ/AAAAAAAAAAI/AAAAAAAAAH0/bANw2nF8nWI/photo.jpg?sz=96",
  "idToken": "redacted"
}

利用Google YOLO上的点击劫持漏洞,攻击者可以获取访问者的姓名、头像和电子邮件地址。没错,攻击者甚至可以知道你的电子邮件地址。:)。现在,Google已经悄悄地“修复”了这个问题,详情请参阅文章的末尾部分。

我向Google报告了这一隐私问题,但他们拒绝解决该问题,因为他们认为这是一个“符合预期的行为”,具体回复如下所示:

Thanks for your bug report and research to keep our users secure! We've investigated your submission and made the decision not to track it as a security bug.

The login widget has to be frameable for it to work. I'm not sure how we could fix this to prevent this problem, but thanks for the report!

This report will unfortunately not be accepted for our VRP. Only first reports of technical security vulnerabilities that substantially affect the confidentiality or integrity of our users' data are in scope, and we feel the issue you mentioned does not meet that bar :(

给我们的启示……


实际上,不要轻易点击任何东西。恶意网站可以轻松地跟踪访问者的光标位置,并相应地改变不可见按钮/iframe的位置。所以,只要你点击了鼠标,攻击者就能迫使你点击他们想要你点击的东西。

注意:这里仅仅给出示意图,实际效果请访问原文

到目前为止,还没有彻底根治点击劫持漏洞的措施;不过,缓解措施还是有的:

  • 网站需要主动部署X-Frame-Options或Content-Security-Policy头部。
  • Web widget供应商需要确保需要提供足够的用户交互。
  • 用户可以考虑禁用第三方cookie。
  • 使用浏览器配置文件。

最后但并非最不重要的是,你还敢点击下面的按钮吗:)?

注意:这里仅仅给出示意图,实际效果请访问原文

更新


在本文发表后不久,Google就悄然地阻止了我的域名使用该API:

The client origin is not permitted to use this API.

最后,祝大家阅读愉快!

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖