《银河边缘》
在这个世界中,有人的地方就有江湖。网络也是一样,由于其相对匿名的特性,其中的攻防甚至更为激烈。
随着智能手机的兴起,越来越多的人开始接入互联网,同时,以此为基础的灰产也在蒸蒸日上。虽然几乎全社会都浸淫在移动互联网中,但技术对他们来说是透明的。对于可用性上来说,这是极好的,能够使得老幼妇孺都能享受到这种便利,但另一方面,由于对技术的不了解,就仿佛随时有无形的杀手潜伏在周围,毫无还手之力。
仅关于“点击链接”,就有各种诈骗相关的新闻,不胜枚举。其中最耸人听闻的是:由于点击了钓鱼链接,导致银行账户直接被洗劫一空。在这个新闻首次被报道时,我妈噤若寒蝉,这些在她眼中似乎都是魔法。那时的我就十分好奇,骗子真有如此神通吗?毕竟人人都得遵循基本的物理呀。
后来我知道,其中一部分原因是很多无良媒体喜欢夸大事实,故意引导公众情绪;另一方面,在网络世界中,由于技术的不成熟或者开发人员的不成熟,存在着一些漏洞。
由于我才疏学浅,只能从最基本处讲起。这篇文章来谈一谈CSRF。
CSRF(Cross Site Request Forgery, 跨站域请求伪造)虽然是一种基本的攻击方式,但是它覆盖面极广,而且常常被忽视。
我记得从初中起,QQ空间常常会出现一些陌生人的留言,内容为:“这是那天我们聚会的照片,我发在这里了:XXX链接”或是“有人把你的照片贴在这里了,这是你吗?XXX链接”。
后来,在每年开学都会收到一份发件人为“教务处”的邮件,内容为:“这是上学期的成绩单”或者“这是这学期的课程安排”等,再配以一张二维码(二维码实质上也是一个链接)。
到如今,时常会在QQ上收到陌生人发来的一份在线共享文档,内容为:“这是近期工作安排”在辅以一条链接。
可见这种基本的攻击方式过了这么多年,依然流行。之所以流行,应该是依然有源源不断的人中招,骗子有利可图。
下面我想谈谈CSRF的基本工作原理,以及如何防范。这有利于你日常多留个心眼谨防上当,其次,假如你是一名入门的开发人员,面试也可能会提及这个问题。
首先稍微解释一下什么是Cookie,以方便后续讲解。
假如你已经登陆了A网站,那么A网站会在你的浏览器端生成你的Cookie,Cookie常常会在本地保存一些你的身份鉴别数据,由于它安全级别并不是很高,所以只要不是特别low的网站,是不会将你的密码保存在Cookie中的。由于http是无状态的,Cookie会保存你的身份鉴别信息,让服务器与你保持连接,以继续此次会话(session)。
此时你已经在A网站通过认证登陆了,Cookie保存在了你的浏览器中,骗子想要从你的浏览器中拿到Cookie是很难的(除非他通过一些社会工程的行为,本篇先不谈)但是他可以让你在不知道的情况下去进行一些他想要的操作。
既然是跨站请求伪造,那么肯定不止一个站点,假设这里有A和B两个站点,A是你经常浏览的正派合法网站——「字节流」(强行推广),B是攻击者自己的服务器。
攻击者是如何控制你的行为的呢?
我曾看到过很多人的QQ空间里发了一些要么与黄色有关,要么与什么微商有关的广告,我觉得他们很可能是中了CSRF(假设,会导致这种效果)。比如攻击者在他引导你点击的链接页面中写了一段js代码(仅简单示例):
然后你就会携带你本地的cookie与这个表单去请求服务器,服务器获取cookie中的与身份有关的信息,并通过了验证,认为你是一个合法的用户,于是将你表单里的内容发布了出去。
至此为止,一次攻击就完成了。
那么如何来访防范这种攻击,浏览器有最基本的跨域检查,即检查请求的发起域与资源的请求域是否一致。但是在H5中,有些标签是可以直接跨域的。最好还是在服务端去抵御这种攻击。首先我们可以考虑一下,造成这种结果的原因在于:
没有验证请求的发起服务器。
无法确定表单是用户主动提交还是被动提交的。
假如让你来设计,该如何应对?同时来看看业界是如何解决的。
Refer
第一种方式,既然没有验证请求的发起服务器,那么我们能不能在通信协议中规定一个属性,即请求者的来源?答案是肯定的,在HTTP header中,有一个Refer属性,即记录了请求者的地址,服务器后端只要验证这个Refer属性的值是否在白名单中即可。
这种方式简单方便,而且它可以与已有的系统解耦,不需要改动其他模块。我以为这样就可以了,但是现实世界往往是复杂的,还有很多其他的因素需要考量。
Refer方式不被常用的原因在于:「Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心 Referer 值会把组织内网中的某些信息泄露到外网中。因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer。当他们正常访问银行网站时,网站会因为请求没有 Referer 值而认为是 CSRF 攻击,拒绝合法用户的访问。」而且,现在Refer值好像也可以篡改了。
Token
第二种方式,从上面的流程可以得知,攻击者无法拿到用户的cookie,也无法拿到服务器返回的数据(同源策略),他能做的只是伪造用户请求。而上文原因之二在于,服务端难以确定表单是用户主动提交,还是在不自知的时候被动提交的。那么,我们可以在请求中加入攻击者难以伪造的元素。
此时可以使用token,token在用户通过验证登入时,由服务器生成返回。token作为该用户网站进行浏览请求的验证信息。token可以放在form或者header中,这个数据是攻击者在自己的服务器无法伪造的,在使用中,我们往往在中间层部署一个nosql类型的数据库,比如redis来进行存储和验证用户的token。
但是需要注意的是,对于用户可以随意发布信息的网站,例如论坛,还需要在前端做额外的判断。因为假如攻击者论坛上发布了自己网站诱导用户去点击,此时前端不能携带token去访问,否则合法用户与他的token将被攻击者获取,并在自己的服务器建立一张映射表,以此来发起新的CSRF。
扫一扫,关注「字节流」