Skip to Content
全部文章前端大杂烩面试常考-现代前端项目如何防范CSRF攻击

面试宝典-前端项目如何防范CSRF攻击

前端面试中,经常会被问到的知识点之一,什么是CSRF攻击?

像鹅厂面试,此问题被问的频率非常之高,而且也是每个项目都很重视的点前端安全点。

什么是CSRF攻击?

表现

首先什么是csrf攻击,官方化的解释是: CSRF(Cross-site request forgery)跨站请求伪造,是一种网络攻击方式,攻击者盗用了你的身份,以你的名义发送恶意请求。

通俗的讲就是,你有一个购物网站域名是gouwu.com,用户在你的网站登录后,登录信息保存到cookie中,此时用户被恶意引导打开了一个eyi.com网站页面。 在eyi.com页面中,执行了一段js代码,请求了gouwu.com网站上真实存在的一个api地址:

fetch('https://gouwu.com/api/order-list',{method:'POST'});

此时,浏览器自动将gouwu.com的cookie带上,这样就可以以用户的身份发送请求给gouwu.com,而gouwu.com也校验了cookie里的令牌,认为用户真实,并将此账号的 购物订单数据返回给了发起求情的eyi.com前端。

像这样的的攻击就是跨站请求伪造,简称CSRF攻击。

危害

从上面的例子可以看出,CSRF攻击的危害是非常大的,攻击者(eyi.com)可以以用户的身份,获取用户在gouwu.com上面的数据,轻则泄漏用户数据,重则 对用户产生经济损失,比如如果我们的gouwu.com不是购物网站,而是银行网站,那攻击者则可以直接通过调用api接口,把用户的钱转走。

防范手段有哪些

CSRF攻击原理

从上面的例子,我们可以看出来,攻击的原理主要是利用了浏览器的cookie机制,在eyi.com发起请求gouwu.com网站的接口, 浏览器在发送请求的时候,会自动gouwu.com带上cookie,导致gouwu.com的服务端只能识别用户登录信息是否有效,但是不能判断这此请求是否是用户的真实访问。

防范手段

当我们知道攻击原理之后,就有防范手段了,防范主要思路主要有3点:

  1. 让eyi.com无法发起请求
  2. 让eyi.com发起请求时不会自动带上gouwu.com的cookie带上
  3. 识别请求是否是用户的真实访问(请求是否是goiuwu.com上触发)

基于这3个思路,我们可以有以下几方面应对措施

跨域资源共享(CORS)

CORS 用于允许浏览器在跨站请求中访问不同源的资源,在上述示例中配置 CORS ,可以让gouwu.com的服务端拒绝非本域名以外的站点向服务器发起请求。

这就解决了上面的第一点,让eyi.com无法发起请求,

比如说express中的配置,类似:

const express = require('express'); const cors = require('cors'); const app = express(); const allowedOrigins = [ 'https://gouwu.com', 'https://gouwu2.com' ]; const corsOptions = { origin: function (origin, callback) { // 如果请求没有源(例如使用 Postman 等工具发出的请求),允许访问 if (!origin) return callback(null, true); // 检查请求的源是否在允许的源列表中 if (allowedOrigins.indexOf(origin) !== -1) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); } } }; // 使用带有配置选项的 cors 中间件 app.use(cors(corsOptions));

这样当gouwu.com的服务端收到请求后,CORS 是一种基于 HTTP 头的机制,W3C 的 CORS 规范明确将 Origin 头作为服务器判断跨域请求是否被允许的关键依据。服务器通过检查 Origin 头,然后根据自身配置的 CORS 策略(如允许的源列表)来决定是否响应请求, 并在响应中添加相应的 CORS 头(如 Access-Control-Allow-Origin)。

Origin受到浏览器的严格保护,不允许直接修改,所以攻击者无法伪造Origin,这样就可以防止CSRF攻击,如果使用非法浏览器或插件,是可以伪造Origin的,但是那已经超出了 本人探讨的CSRF攻击的范畴了。

Cookie安全性设置

通常我们的登录信息都会存在Cookie中,通常服务端在种Cookie的时候有3个比较重要的属性。

他们可以解决上面的第二点,让eyi.com发起请求时不会自动带上gouwu.com的cookie。

  • SameSite

SameSite 属性用于控制 Cookie 在跨站请求时的发送行为,它有三个可选值:

Strict: 说明:当 SameSite 设置为 Strict 时,浏览器在跨站请求中不会发送该 Cookie。也就是说,只有当请求的源(协议、域名和端口)与设置 Cookie 的源完全相同时,才会发送该 Cookie。 适用场景:适用于对安全性要求极高的场景,比如涉及用户资金操作、敏感信息修改等操作的 Cookie。

Lax 说明:Lax 是一种较为宽松的策略。在跨站请求中,只有当请求是顶级导航(如用户点击链接)且为 GET 请求时,才会发送该 Cookie;对于其他类型的跨站请求(如 POST 请求、表单提交等),不会发送 Cookie。 适用场景:适用于一些需要在一定程度上支持跨站请求的场景,同时又要保证一定的安全性,比如用户通过外部链接访问网站。在部分浏览器,不设置时,默认为 Lax。

None 说明:None 表示该 Cookie 可以在跨站请求中发送,但前提是必须同时设置 Secure 属性为 true,即只能通过 HTTPS 协议传输。 适用场景:当网站确实需要在跨站请求中使用 Cookie 时可以使用,但要确保使用 HTTPS 协议。

为了防范csrf攻击,通常cookie都推荐设置为 strict

// 在 Express 框架中设置 SameSite res.cookie('session_id', '123456', { sameSite: 'strict'});
  • Secure

说明:Secure 属性设置为 true 时,浏览器只会在使用 HTTPS 协议的请求中发送该 Cookie。这可以防止 Cookie 在传输过程中被中间人截获。 2025年了,朋友们,请打开你们站点的https吧,并且设置cookie的secure属性为true

res.cookie('session_id', '123456', { sameSite: 'strict', secure: true});
  • HttpOnly

说明:当 HttpOnly 属性设置为 true 时,该 Cookie 只能通过 HTTP 或 HTTPS 请求访问,不能通过 JavaScript 脚本访问。这样可以防止攻击者通过注入恶意脚本获取用户的 Cookie 信息。 对于存储用户敏感信息(如会话 ID)的 Cookie,都应该设置 HttpOnly 属性。 可以防止 XSS 攻击,因为 XSS 攻击通常是通过注入恶意脚本获取用户的 Cookie 信息,进而冒充用户发起请求,所以也请打开你们站点的httponly属性吧。

// 在 Express 框架中设置 SameSite 为 None 并启用 Secure res.cookie('session_id', '123456', { sameSite: 'strict', secure: true, HttpOnly: true});

登录信息的cookie设置了这些属性后,其实就可以防范csrf攻击了,因为攻击者无法在自己的域名下发起伪造请求并带上用户的cookie信息,后面的工作都是浏览器来做了,还是 那句话,如果你用非法浏览器、非法插件实现的伪造请求,那不属于csrf防范的范畴了。

CSRF令牌

CSRF 令牌是另一种防范手段,原理是服务端给自己可信的web页面内注入一个随机的token,然后在发起请求时,将这个token带上, 服务端在接收到请求后,校验这个token是否合法,如果合法则继续处理请求,否则拒绝请求。在早期的express、koa等框架中内置了这些功能。

一句话描述大致实现原理:

  • gouwu.com打开后,服务端在html中插入一个隐藏、随机生成的随机串token,每一次请求都把这个token带上发到服务器上,服务器校验这个token的有效性。

这样就可以判断出某一次请求时否是用户真实发起的请求,有的朋友可能会发现这里有一个“bug”,eyi.com也可以去fetch这个html来拿到这个token,然后再发起请求, 事实上这有悖于浏览器的 同源策略

  • 同院策略

同源策略是浏览器的核心安全机制之一。它规定浏览器从一个源(协议、域名和端口的组合)加载的资源,默认情况下只能访问同源的资源。当恶意网站尝试通过 JavaScript 代码请求目标网站的表单页面时,由于源不同,浏览器会阻止恶意网站的脚本访问表单中的内容,包括隐藏的 CSRF 令牌字段。

假设用户在 https://example.com 登录了一个网站,该网站在表单中包含了 CSRF 令牌。恶意网站 https://malicious.com 尝试使用 JavaScript 的 XMLHttpRequest 或 fetch API 去请求 https://example.com 的表单页面,浏览器会根据同源策略拒绝这个请求,使得恶意网站无法获取表单中的 CSRF 令牌。

通过验证csrf令牌的方法,就可以验证请求时否来自于gouwu.com网站本身的页面,而不是其他的页面,这样就可以防范csrf攻击了。

双重验证

对于以上三点,已经可以杜绝大部分的csrf攻击,但是有的时候,我们还是需要一些额外的验证,比如非常重要的操作,转账、修改密码、删除账号等等, 通常这些敏感度高的操作还可以要求用户进行双重验证,验证手段通常有:

  • 短信验证码
  • 二次输入密码
  • 邮箱验证
  • TOPO(Time-based One-Time Password,基于时间的一次性密码)

这种终极手段,可以为高敏感接口提供绝对的安全保护,避免用户被攻击者利用csrf攻击进行恶意操作。

上面的验证方式我们要全用上吗?

我的个人观点是,一般项目配置好cookie的安全性设置、cors配置就可以了,高敏感接口要接入双重验证,双重验证不单单是保证csrf攻击,就算用户用了非法浏览器, 非法人员获取到用户的所有数据、登录态等,仍然可以保障用户不遭受重大安全影响。

最后编辑于

hi