一.简介
CSRF 英文全称是 Cross-site request forgery,所以又称为“跨站请求伪造”,也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。**跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。 **
对于大多数站点,浏览器请求将自动包括与该站点相关联的任何凭据,例如用户的会话cookie,IP地址,Windows域凭据等。因此,如果用户当前已通过站点认证,则该站点将无法区分受害者发送的伪造请求和受害者发送的合法请求。
简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
二.CSRF攻击方式
下面先看一个CSRF经典攻击例子,用户A通过银行提供的URL地址进行转账户操作:
用户A通过GET向银行站点发起请求,此时的用户A已经是被认证的状态了,它的浏览器中的Cookie缓存着已经认证的会话ID(这是1步骤)
黑客在另一个网站(第三方站点),放置上图中隐藏在图片资源中的恶意转账需求的链接。如果用户A访问了这个第三方的站点(这是步骤2),由于他之前刚访问银行站点不久,登录的信息尚未过期,此时银行站点对用户浏览器是充分信任的,无论啥请求照单全收,页面加载时,浏览器就自动发起了img中资源请求,银行站点无法分辨出是否是用户A的真实操作,因此用A损失了1000刀,心好疼啊!
1.自动发起GET请求的CSRF
从上述的例子可以知道,黑客实施的攻击方式是自动发起GET请求,这同时也是黑客最简易和常用的方式,这种恶意的网址可以有很多种形式,藏身于网页中的许多地方,例如可以插入url的一些地方
<img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">
2.自动发起POST请求的CSRF
除了自动发起get请求之外,有些站点服务器接口使用的POST方法,此时黑客可以在该站点上潜伏伪造POST请求,一般在论坛,博客等任何用户生成内容的网站中都可能是攻击发源地。当用户访问黑客的站点的,就会自动触发POST请求,如自动触发表表单提交:
<html>
<body>
<form class="hacker" action="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman" method=POST>
<input type="hidden" name="account" value="用户A" />
<input type="hidden" name="for" value="hacker" />
<input type="hidden" name="amount" value="1000" />
</form>
<script> document.getElmentsByClassName("hacker").submit(); </script>
</body>
</html>
3.诱导用户点击链接的CSRF
如下图,所示,真的陌生网站链接不要随便点,尤其是关乎钱,要仔细看,有些网站伪装太像了。
同以上两个请求类似,一旦你点击图中领奖的链接,那么你很可能就访问到了黑客站点,那里预设了一个圈套,等你去触发,从而造成你的财务上的损失。
三.防止CSRF攻击策略
以上了解到了三种黑客经常采用的攻击方式,根据去其攻击流程,可以发现以CSRF攻击的特征,想要成功实施一次CSRF必须具备以下几点特征:
CSRF的特征:
- 用户登录过目标站点,获得过身份认证并且在浏览器上保持着该站点的登录状态
- 用户需要访问一个第三方站点,一般是黑客站点,论坛等,进而发起跨站请求。
- 目标站点存在一定的CSRF漏洞
- 攻击者并不能通过CSRF攻击来直接获取用户的账户控制权,也不能直接窃取用户的任何信息,仅冒用。
具备了以上条件后,CSRF攻击就开始进行了,前面提到过跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任,对服务器发起攻击,被攻击的服务器是是可以从阻断攻击,或者正面刚,提高自身的攻击能力来提高安全性,主要有以下几个主流的方法:
1.利用Cookie的SameSite属性
该SameSite属性使服务器要求cookie不应与跨站点请求一起发送(该站点由可注册域定义),这为跨站点请求伪造攻击(CSRF)提供了一些保护。
从上述的例子CSRF攻击中一个特征就是,黑客会利用用户未过期的登录状态,即用户浏览器中Cookie缓存的已经认证的会话ID.来发起CSRF攻击
要找阻止黑客通过冒用用户登录信息进行CRSF攻击,就要在Cookie这个关键字上面施加一些手段
SameSite属性主要做两件事,第一个就是控制跨站点访问,第二就是保证同一站点的稳定安全访问。CSRF攻击都是从第三方站点发起了,在浏览器分辨不出好坏请求时,通过一些属性值可以有效限制Cookie的发送。如在http相应头中:
Set-Cookie: mykey=myvalue; SameSite=Strict
它有三个可能的值:Strict,Lax,和None。
- Strict 最为严格:使用Strict,Cookie仅发送到与它相同的URL。例如你在登录微薄后,如果其用来认证客户的登录状态的Cookie被设置成了Samesite=Strict,当你从其他页面,比如说百度,qq上获取链接点击进入微薄的时候,你的微博是不会处于登录状态的,因为微博这个站点(服务器),不会接受你一个来自百度,qq页面(第三方站点)的Cookie,就好像第一次来一样,就是个路人。
- Lax:Lax不同之处在于用户何时从外部站点导航至URL,例如通过链接进行导航; 但如果在第三方站点中使用 Post 方法, 或者通过 img、iframe 等标签加载的 URL,这些场景都不会携带 Cookie
- None:对跨站点请求没有任何限制。
值得注意的是浏览器正在迁移,以将Cookie设置为SameSite=Lax。但是并非所有的默认浏览器都是这样,如果需要跨域发送cookie,需要显式的设置None属性值选择退出SameSite限制。还必须将Secure属性添加到SameSite=None cookies中。如:
Set-Cookie: mykey=myvalue; SameSite=none;Secure
对于防范 CSRF 攻击,根据具体的应用场景将一些些关键的 Cookie 设置为 Strict ,Lax 或者None模式,这样在跨站点请求时,这些关键的 Cookie 就不会被发送到服务器,从而使得黑客的 CSRF 攻击失效。
2.检查Referer和Origin 属性
HTTP头中有一个Referer字段,这个字段用以标明请求来源于哪个地址。在处理敏感数据请求时,通常来说,Referer字段应和请求的地址位于同一域名下。
以上文银行操作为例,Referer字段地址通常应该是转账按钮所在的网页地址,应该也位于www.examplebank.com之下。而如果是CSRF攻击传来的请求,Referer字段会是包含恶意网址的地址,不会位于www.examplebank.com之下,这时候服务器就能识别出恶意的访问
这种办法简单易行,工作量低,仅需要在关键访问处增加一步校验。但这种办法也有其局限性,因其完全依赖浏览器发送正确的Referer字段。
虽然http协议对此字段的内容有明确的规定,但并无法保证来访的浏览器的具体实现,亦无法保证浏览器没有安全漏洞影响到此字段。并且也存在攻击者攻击某些浏览器,篡改其Referer字段的可能。所以浏览器提供给开发者一个选项,可以不用上传 Referer 值,可参考具体使用参考Referrer-Policy |MDN
因此标准委员会又制定了Origin 属 性,请求首部字段 Origin 指示了请求来自于哪个站点。该字段仅指示服务器名称,并不包含任何路径信息(处于安全考虑)。该首部用于 CORS 请求(XMLHttpRequest、Fecth )或者 POST 请求。除了不包含路径信息,该字段与 Referer 首部字段相似。例如
Origin: https://developer.mozilla.org
服务器的策略是优先判断 Origin,如果请求头中没有包含 Origin 属性,再根据实际 情况判断是否使用 Referer 值。
3.添加校验token
由于CSRF的本质在于攻击者欺骗用户去访问自己设置的地址,所以如果要求在访问敏感数据请求时,要求用户浏览器提供不保存在cookie中,并且攻击者无法伪造的数据作为校验,那么攻击者就无法再运行CSRF攻击.主要分为以下两步:
**第一步: **这种数据通常是窗体中的一个数据项。服务器将其生成并附加在窗体中,其内容是一个伪随机数。当客户端通过窗体提交请求时,这个伪随机数也一并提交上去以供校验。例如通过以下函数去生成:
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
//这个cookie字符串是否以我们想要的名称开头?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
**第二步:**正常的访问时,客户端浏览器能够正确得到并传回这个伪随机数,而通过CSRF传来的欺骗性攻击中,攻击者无从事先得知这个伪随机数的值,服务端就会因为校验token的值为空或者错误,拒绝这个可疑请求。
更多具体实践操作请参考:Cross Site Request Forgery protection | Django documentation | Django. docs.djangoproject.com. [2020-01-21].
小结
应该遵循以下原则来防御CSRF
具体方式见跨站点请求防伪备忘单
- 检查您的框架是否具有内置CSRF保护并使用它
- 如果框架没有内置的CSRF保护,则将CSRF令牌添加到所有状态更改请求(导致在站点上执行操作的请求),并在后端对其进行验证
- 始终对会话cookie 使用SameSite Cookie属性
- 在“深度缓解”部分中实施至少一项来自防御的缓解
- 使用自定义请求标头
- 使用标准标题验证来源
- 使用双重提交Cookie
- 考虑为高度敏感的操作实施基于用户交互的保护
- 请记住,任何跨站点脚本(XSS)都可以用来击败所有CSRF缓解技术!
- 有关如何防止XSS缺陷的详细指南,跨站点脚本防护备忘单
- 不要将GET请求用于状态更改操作。
- 如果出于任何原因这样做,则还必须保护这些资源免受CSRF的侵害
参考资料:
共同学习,写下你的评论
评论加载中...
作者其他优质文章