CSRF是什么?有效的防御措施有哪些?

很多厂在面试的时候,都喜欢问一下关于web安全的问题,比如接下来要说的这个,什么是CSRF以及防范措施有哪些?这文章会带你搞懂CSRF。

什么是CSRF?

(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式。

我们通过一个例子来了解它:

小明登陆了一个银行网站 www.bank.com ,银行服务器发来了一个cookie,

Set-Cookie:id=a3fWa;

后来小明又访问了一个恶意网站 www.hacker.com, 这个恶意网站中有一个表单

<form action='www.bank.com/transfer' method='POST'>
  ...
</form>

小明无意间触发了这个表单,银行服务器会收到带有正确cookie的请求,然后银行服务器会执行自己定义的操作transfer,这个时候就有可能把小明账户的钱给转走。

CSRF特点

  1. 攻击一般发生在第三方网站,而不是被攻击网站;
  2. 攻击利用用户在被攻击网站的登陆凭证(cookie),冒充受害者提交操作,而不是直接窃取数据;
  3. 整个过程,攻击者并不能获取到登录凭证,而是冒用;
  4. 跨站请求可以用各种方式:img图片的src、a标签、form表单提交等等;

你说可怕不可怕?当然可怕,那需要怎么防止CSRF攻击呢?你可能会说,用户不点击进入恶意网站不就行了。这当然可以,但是你不能保证每个人都不去点击恶意网站,所以我们还是要做自动防御,就算用户访问了恶意网站,也要保证我们的网站不会收到攻击。

防御措施

我们知道,CSRF一般发生在第三方网站,而且攻击者只是冒用登录凭证而不是获取登录凭证数据,所以我们制订以下防范策略:

  • 阻止不明外部域名的访问

    • 同源检测
    • Samesite Cookie
  • 提交Form表单时,添加本域才能获取的验证信息

    • CSRF token

1. 同源检测

Cookie的同源和浏览器的同源策略有所区别:


* 浏览器同源策略:协议、域名和端口都相同即同源;
* Cookie同源策略:域名相同即同源;

在HTTP协议中,每个异步请求都会携带两个header,用来标记来源域名:

* Origin Header
* Referer Header

这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端修改,服务器接收到后可以根据这两个Header确定来源的域名;

特殊情况: 如果Origin和Referer都不存在,建议直接进行阻止,特别是如果您没有使用随机CSRF Token(参考下方)作为第二次检查。

另外,CSRF大多数情况下来自第三方域名,但并不能排除本域发起。如果攻击者有权限在本域发布评论(含链接、图片等),那么它可以直接在本域发起攻击,这种情况下同源策略无法达到防护的作用。

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

2. Samesite Cookie属性

Chrome 51版本 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击。

Cookie的Samesite属性用来限制第三方Cookie, 从而减少安全风险,它有三个值:

Set-Cookie: SameSite = Strict;
Set-Cookie: SameSite = Lax;
Set-Cookie: SameSite = None;

Strict: 最为严格,完全禁止第三方Cookie, 跨站点时,任何情况都不发送Cookie;
Lax: 限制稍微宽松,大多数情况下时不发送第三方Cookie的,除了a链接、预加载请求和GET表单;
None: 关闭SameSite属性,但必须同时设置Secure属性,如下:

Set-Cookie: SameSite = None  // 无效
Set-Cookie: SameSite = None; Secure  // 有效

设置了StrictLax,基本就能阻止CSRF攻击,前提是浏览器支持SameSite属性。

3.CSRF token

CSRF攻击之所以能够成功是因为服务器把攻击者携带的Cookie当成了正常的用户请求,那么我们可以要求所有用户请求都携带一个无法被攻击者劫持的token,每次请求都携带这个token,服务端通过校验请求是否为正确token,可以防止CSRF攻击。

CSRF token的防护策略分为三步:

  1. 将token输出到页面
    首先,用户打开页面的时候,服务器需要给这个用户生成一个Token,该Token通过加密算法对数据进行加密,一般Token都包括随机字符串和时间戳的组合,显然在提交时Token不能再放在Cookie中了,否则又会被攻击者冒用。
  2. 请求中携带token
    对于GET请求,将token附在请求地址之后,如:http://url?token=tokenValue
    对于POST请求,要在Form表单后面加上

    <input type=”hidden” name=”token” value=”tokenvalue”/>
  3. 服务端验证token是否正确
    服务端拿到客户端给的token后,先解密token,再比对随机字符串是否一致、时间是否有效,如果字符串对比一致且在有效期内,则说明token正确。

总结

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

  • 自动防护策略:同源检测(OriginReferer验证);
  • 主动防护策略:token验证以及配合SameSite设置;
  • 保护页面的幂等性,不要再GET请求中做用户操作

为了更好的防御CSRF,最佳实践应该是结合上面总结的防御措施方式中的优缺点来综合考虑,结合当前Web应用程序自身的情况做合适的选择,才能更好的预防CSRF的发生。


前端_风雨开发路
用心整理web前端开发过程中遇到的坑和绕过的弯,希望能帮助到茫茫人海中的你!

灵魂和皮囊能够握手言和,面子和里子能够始终如一。

272 声望
15 粉丝
0 条评论
推荐阅读
「多图预警」完美实现一个@功能
一天产品大大向 boss 汇报完研发成果和产品业绩产出,若有所思的走出来,劲直向我走过来,嘴角微微上扬。产品大大:boss 对我们的研发成果挺满意的,balabala...(内心 OS:不听,讲重点)产品大大:咱们的客服 I...

wuwhs40阅读 4.8k评论 5

封面图
ESlint + Stylelint + VSCode自动格式化代码(2023)
安装插件 ESLint,然后 File -&gt; Preference-&gt; Settings(如果装了中文插件包应该是 文件 -&gt; 选项 -&gt; 设置),搜索 eslint,点击 Edit in setting.json

谭光志34阅读 20.8k评论 9

安全地在前后端之间传输数据 - 「3」真的安全吗?
在「2」注册和登录示例中,我们通过非对称加密算法实现了浏览器和 Web 服务器之间的安全传输。看起来一切都很美好,但是危险就在哪里,有些人发现了,有些人嗅到了,更多人却浑然不知。就像是给门上了把好锁,还...

边城32阅读 7.3k评论 5

封面图
涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco24阅读 2.3k评论 3

你可能不需要JS!CSS实现一个计时器
CSS现在可不仅仅只是改一个颜色这么简单,还可以做很多交互,比如做一个功能齐全的计时器?样式上并不复杂,主要是几个交互的地方数字时钟的变化开始、暂停操作重置操作如何仅使用 CSS 来实现这样的功能呢?一起...

XboxYan25阅读 1.7k评论 1

封面图
在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 2k

封面图
过滤/筛选树节点
又是树,是我跟树杠上了吗?—— 不,是树的问题太多了!🔗 相关文章推荐:使用递归遍历并转换树形数据(以 TypeScript 为例)从列表生成树 (JavaScript/TypeScript) 过滤和筛选是一个意思,都是 filter。对于列表来...

边城18阅读 7.8k评论 3

封面图

灵魂和皮囊能够握手言和,面子和里子能够始终如一。

272 声望
15 粉丝
宣传栏