安全 – CSRF

主要参考:

WEB安全之-CSRF(跨站请求伪造)

SameSite Cookie,防止 CSRF 攻击

跨站请求伪造与 Same-Site Cookie

ASP.Net Core: X-Frame-Options strange behavior

Preventing Cross-Site Request Forgery (CSRF) Attacks in ASP.NET MVC Application

Using Anti-Forgery Tokens in ASP.NET 5.0 Razor Pages

 

什么是 CSRF

CSRF 是 Cross site request forgery,中文叫跨站请求伪造。

讲的就是 Cookie 被 hack,然后可以假冒用户去做坏事。

 

攻击场景

小明访问 bank.com,登入后有了 Cookie,然后他去访问 hacker.com。

hacker.com 提交了一个表单给 bank.com。

由于表单是提交给 bank.com 游览器会携带 bank.com 的 Cookie。

bank server 会把这个请求当成一般的请求处理,然后钱就被转走了。

所以早年我们通常会教育世人,你登入了银行就不要乱乱点链接,做完事情就登出。

 

传统解决方案

上面的关键就是 bank server 需要确保请求是来自 bank.com 而不是 hacker.com 的。

这样就破了,从前的解决方案是这样的:

访问 bank.com 某个 form submit 的页面时,bank.com 会生成一个随机数放到 form 的 hidden field 里。

同时这个随机数也被写入 Cookie 里。

当用户提交 form 的时候,bank server 会检查 hidden filed 的随机数和 Cookie 里的是否相同,如果相同那么就表示请求来自 bank.com。

现在 hacker.com 如果要假冒的话,它提交的 form 也必须包含一个随机数,而这个随机数必须和 Cookie 里的一样。

hacker.com 有没有办法获取到这个随机数呢? 

第一个随机数在 back.com hidden field,这个自然拿不到。

第二个随机数在 Cookie 里,hacker.com 虽然可以在发请求的时候带上 back.com 的 Cookie,但是它却无法读取这个 Cookie 的 value (不同域,所以读不到)

所以结论是 hacker.com 无法获取到随机数,那自然也就没有办法伪造 form 提交了。

 

现代解决方案

传统的方案一直沿用到今天,毕竟成本不高嘛,而且大部分都是框架自带的。

现代的解决方案的思路是:

跨站请求干脆就不带 Cookie 了。所以 hacker.com 发的请求完全就没有 bank.com 的 Cookie,那就什么也不用想 hack 了。

当然也不能这么过分,没有 Cookie 有时候也很难做事情,所以就有了一个折中方案,GET 请求可以带 Cookie,其它的就不行。

这就是 Cookie same-site Strict 和 Lax 了,back.com 在 response Cookie 时设定好 Cookie same-site 策略。

Strict 是严格模式,只要不同域就不发 Cookie,包括跳转 和 get 请求,但这个不是很好用,比如 a 网站点击链接去到了 b 网站,结果 b 网站的 Cookie 没有效果。

所以大部分时候用 Lax,Lax 不会限制安全请求,比如 get 的时候依然会带上 Cookie 的,POST 就不带。

另外说一下,get 请求和 CSRF:

可能我们会想,hacker.com 如果发一个 get 请求去查看我银行的余额可以吗? 

其实是不可以的, 游览器会有 cross domain 防御,虽然请求依然会被 server 处理,但是游览器接收后,发现服务端不允许跨域,那它就不会运行后续的 JS,所以是安全的。

 

常见疑惑

  1. 如果我没有使用 Cookie 还需要担心这些吗?
    不需要,它只是 hack Cookie 而且。
  2. same site 是不是可以替代传统的 Anti Foreign Token 方案?
    是,前提是用户的游览器必须是 modern browser,IE 是不支持的。
  3. Ajax Bearer Token 是不是不需要 care 这些了?
    是,Bearer Token 就等于不使用 Cookie 了。
  4. GET 请求为什么不可以有 side effect?
    顺风水,比如 same site Lax 的情况下,GET 请求是带 Cookie 的,如果你把 GET 做成可以有 side effect 的话,那么 same site 就保护不了了。

 

ASP.NET Core – CSRF

services.AddAntiforgery 就是防 CSRF 的。

调用下面其中一个它就会被启动了,所以大部分情况不需要手动开启。

它里面还有保护 clickJacking 哦,不过它只在有 set Cookie 的情况下才会保护 (也就是当有做 Anti Foreign Token 出来的时候, anti foreign token 是存在 Cookie 的)

所以如果我们不想被其它网站 iframe 嵌套的话,那不能依靠它,还是自己 set 一个 CSP 妥当。

Razor pagas 默认就会检查。

<form method="post" > 没有声明 action 就是 POST 去当前页面,它自己会把 Anti Token 放进去 input hidden,然后 POST 的时候也会检查。我们什么都不需要做。

但最好是加上 asp- 指令不管是 asp-for, asp-page 都 ok。

如果像下面这种情况,没有用到 asp- 又是 action to 另一个 page,它会报 400 error 哦。

需要加入 asp-antiforgery="true",或者写成 action="~/account/logout" 也可以,关键就是 ASP.NET Core 需要有个识别方式 (不要问我为什么 form 它认不出来...)

<form method="post" action="/account/logout" asp-antiforgery="true">
    <button>Logout</button>
</form>

Web API 的话就没有自动检查了。

可以学 angularjs 的做法,放入到 header 里。

然后 backend manual check,很简单而已。

 

posted @ 2019-04-27 18:39  兴杰  阅读(267)  评论(0编辑  收藏  举报