CSRF概述和Beego配置

CSRF概述

攻击发生是因为攻击者诱导用户在已登录的网站上执行非预期的操作。攻击者利用用户的身份认证信息,伪造请求,从而在用户不知情的情况下执行某些操作。

1.CSRF攻击是如何发生的?

a.用户登录受信任的网站:用户登录一个受信任的网站,比如银行网站或邮箱系统,此时用户的浏览器会存储该网站的会话信息(如 Cookie)。
b.攻击者构造恶意请求:攻击者构造一个恶意请求(通常是 HTML 链接或表单),该请求的目标 URL 指向受信任网站的某个操作页面,例如转账操作或修改密码等。
c.用户被诱导点击恶意请求:攻击者通过邮件、即时消息或其他方式,诱导用户访问包含恶意请求的页面。
d.用户浏览器自动发送认证信息:用户在不知情的情况下点击了恶意链接或提交了恶意表单,用户的浏览器会自动附带受信任网站的会话信息(如 Cookie)发送请求。
e.受信任网站执行操作:受信任网站收到请求后,认为该请求是合法的用户操作,从而执行相应的操作,例如转账或修改密码。

2.防止CSRF攻击的措施
a.使用CSRF令牌:在每个表单中加入一个随机生成的CSRF令牌,并在服务器端进行验证。如果请求中没有包含有效的CSRF令牌,则拒绝该请求。
b.验证HTTP请求头:检查 Referer 和 Origin请求头,确保请求来自受信任的来源。
c.使用SameSite Cookie属性:将Cookie的SameSite属性设置为Strict或Lax,防止跨站请求自动附带Cookie。
c.用户交互验证:在关键操作前增加用户交互步骤,如输入验证码或重新输入密码。

3.CSRF令牌怎么起作用的?

a.使用CSRF令牌:在每个表单中加入一个随机生成的CSRF令牌,并在服务器端进行验证。如果请求中没有包含有效的CSRF令牌,则拒绝该请求。
b.验证HTTP请求头:检查 Referer 和 Origin请求头,确保请求来自受信任的来源。
c.使用SameSite Cookie属性:将Cookie的SameSite属性设置为Strict或Lax,防止跨站请求自动附带Cookie。
d.用户交互验证:在关键操作前增加用户交互步骤,如输入验证码或重新输入密码。

在 Beego 中开启 XSRF 后,通常需要使用 HTTPS 才能正常访问,即使是本地访问。这是因为在 Beego 2.x 及以上版本中,存储 XSRF Token 的 Cookie 默认带有 Secure 和 HTTP-ONLY 标志。这意味着 Cookie 只会在 HTTPS 协议下被发送,并且无法通过 JavaScript 访问,从而增强了安全性。

4.CSRF令牌怎么生成的,又怎么起作用的?

1)令牌生成:

服务器端令牌生成:当用户登录或会话开始时,服务器会生成一个唯一的CSRF令牌。这个令牌通常是随机生成的字符串,具有足够的长度和复杂性,以防止猜测攻击。例如,使用Python的secrets模块可以生成一个安全的随机令牌:

secrets.token_hex(16)

存储令牌:生成的CSRF令牌会被存储在用户的会话数据中。每次用户访问需要保护的页面时,服务器会将该令牌嵌入到页面的表单中,作为一个隐藏字段。例如,在HTML表单中添加:

1
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">

2)令牌作用:

验证请求来源:当用户提交表单时,服务器会检查请求中的CSRF令牌是否与会话中存储的令牌一致。如果一致,则认为请求是合法的,允许继续处理;如果不一致或令牌缺失,则拒绝请求。

防止CSRF攻击:由于CSRF令牌是随机生成且与用户会话绑定的,攻击者无法获取或预测该令牌。即使攻击者诱导用户发送了恶意请求,服务器也会因缺少有效的CSRF令牌而拒绝该请求。

5.CSRF(跨站请求伪造)令牌通常无法被攻击者从页面中直接盗取,原因如下

1)CSRF令牌存储在会话中:
CSRF令牌是服务器端生成的随机字符串,与用户的会话绑定。服务器会将该令牌存储在用户的会话数据中,而不是直接暴露在页面的HTML中。
2)CSRF令牌在HTML中隐藏:
尽管CSRF令牌也会被嵌入到页面中,通常是作为表单的隐藏字段或在JavaScript脚本中,但它不会直接暴露在页面的HTML中。即使攻击者能查看页面的HTML,他们也不一定能获取到有效的CSRF令牌。
3)CSRF令牌的随机性:
CSRF令牌是随机生成的,并且具有足够的长度和复杂性,使得攻击者无法轻易猜测或预测。即使攻击者能查看页面的HTML,他们也无法提前知道或伪造有效的CSRF令牌。
4)同源策略的限制:
浏览器的同源策略阻止了不同域之间的脚本交互,这限制了攻击者通过脚本访问其他域的页面内容。即使攻击者能诱导用户访问恶意页面,他们也无法通过脚本读取其他域的页面内容(包括CSRF令牌)。
5)CSRF验证机制:
当用户提交表单时,服务器会验证表单中的CSRF令牌是否与会话中的令牌一致。如果令牌不一致或缺失,服务器会拒绝请求。
因此,即使CSRF令牌在页面中,攻击者也很难直接盗取或利用它。CSRF防护机制通过结合随机令牌生成、会话绑定和同源策略限制,有效地防止了CSRF攻击。

6.CSRF的存储安全

1)服务器端会话存储(Session)
什么是会话(Session):当用户登录网站时,服务器会为该用户创建一个会话,用于存储用户的相关数据(如用户ID、登录状态等)。会话数据通常存储在服务器端(如内存、数据库或缓存系统中)。
CSRF令牌存储位置:服务器生成CSRF令牌后,会将其存储在服务器端的会话数据中。每次用户请求页面时,服务器会将CSRF令牌嵌入到页面的表单中作为隐藏字段,或者通过JavaScript代码传递给客户端。

2)客户端Cookie存储
什么是Cookie:Cookie是服务器发送给浏览器的小段文本信息,浏览器会将其存储在本地,并在后续请求中自动发送回服务器。
CSRF令牌存储位置:服务器可以将CSRF令牌存储在Cookie中。浏览器在发送请求时会自动附带该Cookie,服务器通过验证Cookie中的CSRF令牌来确保请求的合法性。

3)两者的结合使用
服务器端验证:当用户提交表单时,服务器会检查表单中的CSRF令牌是否与会话中存储的令牌一致。如果一致,则认为请求是合法的;如果不一致或令牌缺失,则拒绝请求。
客户端验证:通过JavaScript代码,可以在客户端读取Cookie中的CSRF令牌,并将其添加到AJAX请求的标头中,以供服务器验证。

7.CSRF令牌存储在Cookie中,也不会轻易被攻击者盗取,原因如下:

1)HttpOnly属性:服务器可以为Cookie设置HttpOnly属性,这样即使攻击者通过XSS漏洞注入脚本,也无法通过JavaScript读取该Cookie中的内容。
2)Secure属性:如果Cookie设置了Secure属性,它只会通过HTTPS协议发送,这可以防止中间人攻击者在不安全的网络上截获Cookie。
3)SameSite属性:通过设置SameSite属性为Strict或Lax,可以限制Cookie在跨站请求中的发送,从而减少CSRF攻击的风险。如果CSRF令牌存储在Cookie中,SameSite属性也可以帮助防止攻击者通过跨站请求获取该Cookie。
4)CSRF验证机制:即使攻击者能够获取到CSRF令牌,服务器端还会验证CSRF令牌的来源和有效性。例如,服务器可以检查请求的Referer头或Origin头,以确保请求来自预期的来源。
因此,CSRF令牌可以存储在Cookie中,只要采取了适当的安全措施(如HttpOnly、Secure和SameSite属性),就可以有效防止令牌被盗取或被滥用。此外,CSRF验证机制本身也会对请求的合法性进行验证,进一步增强了安全性。

Beego配置CSRF

Beego如何保证不被攻击到的
Beego 提供了内置的 CSRF 防护功能,其基本原理是为每个用户生成一个随机的 CSRF 令牌,并将其存储在用户的 Cookie 中。在所有表单提交的请求中,必须包含这个令牌值。如果请求中的令牌值与 Cookie 中的不匹配,则该请求会被认为是伪造的并被拒绝。

当 CSRF 防护启用时,Beego 会在后台自动验证所有 POST、PUT、DELETE 请求中的_xsrf参数,而无需显式编写验证代码。如果请求中缺少_xsrf参数或者值不匹配,Beego 会自动返回一个错误页面,报错信息为 '_xsrf' argument missing from POST。这是 Beego 内置的机制,用户无需额外处理。

Beego配置

1
2
3
4
5
enablexsrf = true//启用 CSRF 防护功能
//用于签名 CSRF Cookie 的密钥
xsrfkey = 61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o
//设置 CSRF Cookie 的过期时间,默认为 3600 秒(1 小时)
xsrfexpire = 3600

Beego后端代码

1
2
3
4
5
6
// 获取 CSRF 令牌
csrfToken := c.XSRFToken()
// 将 CSRF 令牌传递给模板
c.Data["xsrfdata"] = csrfToken
//注册登录模板
c.TplName = "test/login.html"

其他接口不需要csrf:在控制器的prepare中

1
2
3
func (p *baseController) Prepare() {
p.EnableXSRF = false
}

Beego前端代码

1
<input type="hidden" name="_xsrf" value="{{ .xsrfdata }}">

默认的服务器会话存储机制可能是内存存储,浏览器中会有对应cookie。浏览器中的_xsrfCookie 是使用配置中的 xsrf key 签名后的结果。
但本地每次服务重启的令牌都一样,改变过期时间都没用。线上服务器停服重启,令牌都一样,过期时间有效,太快过期导致登录不了,所以过期时间还是3600s的好。
最佳实践:每次会话生成一个新的随机令牌,并在会话结束时销毁,以防止令牌被泄漏或重放攻击,请求中加入随机性来增强安全性。

Beego 内置 CSRF :对性能的影响相对较小,但对于高并发场景可能不够高效。
gorilla/csrf :由于其灵活性和强大的功能,在性能上可能稍逊于 Beego 内置的 CSRF,但在优化和缓存的支持下,性能影响是可以接受的。

CSRF攻击实际例子

1.银行转账攻击
用户登录受信任的网站:用户登录了 Acme Bank 的网上银行系统,银行会为用户分配一个会话 Cookie。
攻击者构造恶意请求:攻击者发现该银行的转账操作存在 CSRF 漏洞,于是构造了一个恶意的 GET 请求,将收款人账号改为自己的账号,并增大转账金额,例如:http://acmebank.com/fundtransfer?acct=224224&amount=50000。
用户被诱导点击恶意请求:攻击者通过邮件或即时消息向用户发送伪装成礼物领取链接的恶意链接,诱导用户点击。
用户浏览器自动发送认证信息:当用户点击链接时,浏览器自动向银行网站发送请求,并附带用户的会话 Cookie。
受信任网站执行操作:银行网站收到请求后,认为该请求是合法的用户操作,执行转账操作,将用户的资金转账到攻击者的账户。
2.修改密码攻击
用户登录受信任的网站:用户登录了某个网站。
攻击者构造恶意请求:攻击者创建了一个与银行原始密码修改表单相似的表单,但将密码值改为攻击者已知的值,并在表单中添加了自动提交的 JavaScript 代码。
用户被诱导点击恶意请求:攻击者将该恶意表单托管在恶意网站上,并通过伪装成银行的电子邮件或链接,诱导用户访问该网站。
用户浏览器自动发送认证信息:当用户访问恶意网站时,浏览器自动向银行网站发送请求,并附带用户的会话 Cookie。
受信任网站执行操作:银行网站收到请求后,认为该请求是合法的用户操作,将用户的密码修改为攻击者设定的密码。
3.uTorrent 攻击
用户登录受信任的网站:用户登录了 uTorrent 的 Web 界面。
攻击者构造恶意请求:攻击者发现了 uTorrent 的 Web 界面存在 CSRF 漏洞,构造了用于下载恶意软件和更改管理员密码的 URL。
用户被诱导点击恶意请求:攻击者在多个互联网论坛上发布包含恶意 HTML 元素的帖子,并发送垃圾邮件,诱导用户访问这些论坛或打开邮件。
用户浏览器自动发送认证信息:当用户访问论坛或打开邮件时,浏览器自动向 uTorrent 的 Web 界面发送请求,并附带用户的会话 Cookie。
受信任网站执行操作:uTorrent 的 Web 界面收到请求后,认为该请求是合法的用户操作,执行下载恶意软件和更改密码的操作,导致用户的设备被恶意软件感染,攻击者可以控制用户的 uTorrent 软件。
4.电商网站购买攻击
用户登录受信任的网站:用户登录了电商网站 examplebuy.com
攻击者构造恶意请求:攻击者观察到该网站的购买请求格式,构造了一个恶意的 GET 请求,使用用户账户购买高价商品,并将收货地址改为自己的地址。
用户被诱导点击恶意请求:攻击者将恶意 URL 隐藏在图片标签中,并嵌入到发送给用户的电子邮件中,诱导用户点击。
用户浏览器自动发送认证信息:当用户打开邮件并加载图片时,浏览器自动向电商网站发送请求,并附带用户的会话 Cookie。
受信任网站执行操作:电商网站收到请求后,认为该请求是合法的用户操作,执行购买操作,将商品发送到攻击者的地址,并从用户账户中扣除费用。