CSRF攻击

1. 什么是 CSRF

CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,来执行某项操作。

2. CSRF 分类

1.GET类型的CSRF

可以完美避过跨域问题

<!DOCTYPE html><html><head><meta charset="utf-8" /><title>csrf_1</title></head><body><img src='http://localhost.meetsocial.cn:8888/update?amount=1111'></body></html>
复制代码

2. POST 类型的跨域问题

若使用 iframe 则更加隐蔽。

<html><head><meta charset="utf-8" /><title>csrf_2</title></head><body><iframe src='https://juejin.cn/post/csrf_iframe.html'></iframe></body></html>
复制代码

iframe 页面 – csrf_iframe.html

<html><head><meta charset="utf-8" /><title>csrf_2</title></head><body><form method="POST" action="http://localhost.meetsocial.cn:8888/update"><input type="hidden" name="amount" value="2222"/></form><script>document.forms[0].submit();</script></body></html>
复制代码

3. 链接类型的CSRF

<html><head><meta charset="utf-8" /><title>csrf_3</title></head><body><a href='http://localhost.meetsocial.cn:8888/update?amount=1234' target="_blank">重磅消息</a></body></html>
复制代码

3.CSRF的特点

1.攻击一般发起在第三方网站,而不是被攻击的网站。

2.攻击利用受害者在被攻击网站的登录凭证(所以有的时候隐私浏览器访问也比较安全),冒充受害者提交操作

3.整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”

CSRF攻击有着如下的流程:

1.受害者登录a.com,并保留了登录凭证(Cookie)。

2.攻击者引诱受害者访问了b.com。

3.b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。

4.a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。

5.a.com以受害者的名义执行了act=xx。

6.攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。

4. 防护策略

1. 同源检测

CSRF大多来自第三方网站, 直接禁止外域。根据 Referer Header 来判断。

这种方法并非万无一失,Referer的值是由浏览器提供的,虽然HTTP协议上有明确的要求,但是每个浏览器对于Referer的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不是很安全。在部分情况下,攻击者可以隐藏,甚至修改自己请求的Referer。

同源验证是一个相对简单的防范方法,能够防范绝大多数的CSRF攻击。但这并不是万无一失的,对于安全性要求较高,或者有较多用户输入内容的网站,我们就要对关键的接口做额外的防护措施。

2. CSRF Token

攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息。

服务器通过校验请求是否携带正确的Token,来把正常的请求和攻击的请求区分开,也可以防范CSRF的攻击。

CSRF Token的防护策略分为三个步骤:

1. 将CSRF Token输出到页面中

服务器需要给这个用户生成一个Token,该Token通过加密算法对数据进行加密,一般Token都包括随机字符串和时间戳的组合

2. 页面提交的请求携带这个Token

对于GET请求,Token将附在请求地址之后,这样URL 就变成 http://url?csrftoken=tokenvalue

而对于 POST 请求来说,要在 form 的最后加上:

3. 服务器验证Token是否正确

Token可以在产生并放于Session之中,然后在每次请求时把Token从Session中拿出,与请求中的Token进行比对。

总结:

Token是一个比较有效的CSRF防护方法,只要页面没有XSS漏洞泄露Token,那么接口的CSRF攻击就无法成功。

但是此方法的实现比较复杂,需要给每一个页面都写入Token(前端无法使用纯静态页面),每一个Form及Ajax请求都携带这个Token,后端对每一个接口都进行校验,并保证页面Token及请求Token一致。

验证码和密码其实也可以起到CSRF Token的作用哦,而且更安全,虽然有的时候比较繁琐。这也是为什么很多银行等网站会要求已经登录的用户在转账时再次输入密码。

2. 双重Cookie验证

在会话中存储CSRF Token比较繁琐, 另一种防御措施是使用双重提交Cookie。

步骤:

1. 在用户访问网站页面时,服务端向请求域名注入一个Cookie,内容为随机字符串(例如csrfcookie=v8g9e4ksfhw)。

2. 在前端向后端发起请求时,取出Cookie,并添加到URL的参数中(接上例POST [https://www.a.com/comment?csrfcookie=v8g9e4ksfhw](https://www.a.com/comment?csrfcookie=v8g9e4ksfhw))。

3. 后端接口验证Cookie中的字段与URL参数中的字段是否一致,不一致则拒绝。

总结:

用双重Cookie防御CSRF的优点:

  • 无需使用Session,适用面更广,易于实施。
  • Token储存于客户端中,不会给服务器带来压力。
  • 相对于Token,实施成本更低,可以在前后端统一拦截校验,而不需要一个个接口和页面添加。

缺点:

  • Cookie中增加了额外的字段。
  • 如果有其他漏洞(例如XSS),攻击者可以注入Cookie,那么该防御方式失效。
  • 为了确保Cookie传输安全,采用这种防御方式的最好确保用整站HTTPS的方式,如果还没切HTTPS的使用这种方式也会有风险。

3.Samesite Cookie

它有3个值:

1. Strict

完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。

但是本页面发送携带跨子域cookie还是可以的, 打开本页面控制台输出如下代码:

fetch('http://david.meetsocial.cn:8888/update', {body: JSON.stringify({amount: 2}),credentials: 'include',method: 'POST'});
复制代码

服务端设置:

if (req.headers.origin) {res.setHeader('Access-Control-Allow-Credentials', 'true');res.setHeader('Access-Control-Allow-Origin', req.headers.origin);}
复制代码

2. Lax

导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。

请求类型

示例

正常情况

Lax

链接

<a href="https://juejin.cn/post/..."></a>

发送 Cookie

发送 Cookie

预加载

<link rel="prerender" href="https://juejin.cn/post/..."/>

发送 Cookie

发送 Cookie

GET 表单

<form method="GET" action="...">

发送 Cookie

发送 Cookie

POST 表单

<form method="POST" action="...">

发送 Cookie

不发送

iframe

<iframe src="https://juejin.cn/post/..."></iframe>

发送 Cookie

不发送

AJAX

$.get("...")

发送 Cookie

不发送

Image

<img src="https://juejin.cn/post/...">

发送 Cookie

不发送

3. None

Chrome 计划将Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None

不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。

将来Chrome的计划下面的设置无效, 目前还是可以。

[document.cookie=](http://conf.meetsocial.cn:6688/pages/document.cookie=)``'aaa=111;SameSite=None;'

并且chrome 会有一个警告:

A cookie associated with a resource at test-sso.meetsocial.cn/ was set with `SameSite=None` but without `Secure`. A future release of Chrome will only deliver cookies marked `SameSite=None` if they are also marked `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at www.chromestatus.com/feature/563….

下面的设置有效:

[document.cookie=](http://conf.meetsocial.cn:6688/pages/document.cookie=)``'bbb=2222;SameSite=None; Secure'

结论:

1. 设置 Lax 并且所有接口都用POST 的方式,就基本可以防范 CSRF 的攻击。

2. 虽然设置 Strict 也支持携带cookie, 但是同时它也阻止了 搜索引擎 点击链接 携带的登录态 cookie, 所以不太推荐。

3. 目前 SameSite 设置 Strict, Lax, None 都支持本页面发送携带跨子域** cookie的请求**, 当前Chrome 版本83, 以前Chrome 版本可能不支持,其它浏览器的兼容性有待考证。

5. 结论

CSRF的攻击可以来自:

1. 攻击者自己的网站。

2. 有文件上传漏洞的网站。

3. 第三方论坛等用户内容。

4. 被攻击网站自己的评论功能等。(直接提交表单评论, 所以验证码也是)

如何防止自己的网站被利用成为攻击的源头呢:

1. 严格管理所有的上传接口,防止任何预期之外的上传内容(例如HTML)。

2. 添加Header X-Content-Type-Options: nosniff 防止黑客上传HTML内容的资源(例如图片)被解析为网页。– 待考证

3. 对于用户上传的图片,进行转存或者校验。不要直接使用用户填写的图片链接。

4. 当前用户打开其他用户填写的链接时,需告知风险(这也是很多论坛不允许直接在内容中发布外域链接的原因之一,不仅仅是为了用户留存,也有安全考虑)。

简单总结一下上文的防护策略:

1. CSRF自动防御策略:同源检测(Origin 和 Referer 验证)。

2. CSRF主动防御措施:Token验证 或者 双重Cookie验证 以及配合Samesite Cookie。

3. 保证页面的幂等性,后端接口不要在GET页面中做用户操作。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享