CSRF介绍与应对策略以及Java代码示例
简介
CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式。
CSRF 攻击实例
CSRF 攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在并未授权的情况下执行在权限保护之下的操作。
场景
假设有两个网站:
bank.com- 一个虚构的银行网站。malicious.com- 一个虚构的恶意网站。
用户 Alice 在 bank.com 上有一个账户,并且当前在 bank.com 上登录状态。
bank.com 允许用户通过一个简单的 URL(例如 https://bank.com/transfer?to=Bob&amount=100)进行转账。这个 URL 会从 Alice 的账户转账 100 个单位到 Bob 的账户。
CSRF 攻击
现在,恶意攻击者知道了 bank.com 的转账 URL 结构。攻击者在 malicious.com 上创建了一个页面,其中包含以下代码:
<img src="https://bank.com/transfer?to=EvilBob&amount=1000" width="1" height="1" /> 当 Alice 访问 malicious.com 时,浏览器会尝试加载上面的图片。这将导致 Alice 的浏览器向 bank.com 发出转账请求,从 Alice 的账户转账 1000 个单位到 EvilBob 的账户。
由于 Alice 当前在 bank.com 上是登录状态,所以她的登录 cookie 会附加到这个请求中(除非这个 cookie 被设置为 SameSite=Lax 或 SameSite=Strict)。这意味着,对于 bank.com 来说,这个请求看起来就像是 Alice 有意识地发出的。
CSRF 攻击的对象
要保护的对象和资源,是那些可以直接产生数据改变的服务,而对于读取数据的服务,则不需要进行 CSRF 的保护。
当前防御 CSRF 的几种策略
一些常见的方法来防止 CSRF 攻击:
-
使用 CSRF 令牌:
- 当用户访问需要保护的表单(例如转账或更改设置的表单)时,服务器生成一个随机的、唯一的令牌,并将其放入表单中。
- 当表单提交时,令牌也会被提交。服务器会验证提交的令牌是否与用户会话中存储的令牌匹配。
- 如果令牌不匹配或缺失,服务器将拒绝请求。
- 这种方法的工作原理是基于攻击者不知道用户的 CSRF 令牌的事实,因此他们不能伪造有效的请求。
- 设置cookie
SameSite属性
SameSite属性可以用来控制浏览器如何与第三方及跨站点请求共享 cookie。-
SameSite 有3个值:
Strict:
Cookie 只会在同一站点 (same-site) 的上下文中被发送。这意味着,只有当请求的来源和目标都是相同的站点时,cookie 才会被发送。
例如,如果你在 example.com 上设置了一个 SameSite=Strict 的 cookie,那么这个 cookie 只会在来自 example.com 的请求中被发送,而不会在来自其他站点的请求中被发送。
Lax:Cookie 会在同一站点的上下文以及部分跨站点的场景下被发送。具体来说,它会在顶级导航(例如,通过链接跳转)时发送,但不会在其他类型的跨站点请求中被发送(例如,嵌入的图片或脚本)。
例如,如果一个用户点击了一个指向 example.com 的链接,即使这个链接是在其他的站点上,一个设置为 SameSite=Lax 的 cookie 也会被发送到 example.com。但是,如果一个嵌入在其他网站上的图片请求 example.com,该 cookie 则不会被发送。
None:Cookie 会在所有请求中被发送,包括跨站点请求。这是以前的默认行为。
为了设置 SameSite=None,你还必须将 Secure 属性设置为 true,这意味着 cookie 只能在 HTTPS 连接上被发送。
在浏览器的最新版本中,如果没有明确设置 SameSite 属性,那么默认值通常是 Lax。这是为了提高安全性,减少 CSRF 攻击的风险。 -
Java(springboot)里设置SameSite属性,由于 Java 的 HttpServletResponse 本身不直接支持设置 SameSite 属性,需要手动构建 Set-Cookie 响应头。以下是一个示例代码:
import javax.servlet.http.HttpServletResponse; @RestController public class MyController { @RequestMapping("/set-cookie") public ResponseEntity<String> setCookie(HttpServletResponse response) { String cookieValue = "someValue"; response.setHeader("Set-Cookie", "myCookieName=" + cookieValue + "; SameSite=Strict; Secure; HttpOnly"); return ResponseEntity.ok("Cookie set"); } }
-
检查 Referer 和 Origin 头:
- 服务器可以检查 HTTP
Referer或Origin头,以确定请求是否来自合法的源。 - 例如,如果
bank.com只接受来自自己网站的请求,那么它可以拒绝任何Referer或Origin不是bank.com的请求。 - 但是,这种方法可能会因浏览器的不同行为或隐私插件而变得不可靠。
- 服务器可以检查 HTTP
-
使用双因素身份验证 (2FA):
- 虽然 2FA 主要是为了增强登录的安全性,但它也可以作为防止 CSRF 攻击的一个障碍。如果一个操作需要 2FA,那么即使攻击者成功地引导用户进行了恶意操作,该操作也会被阻止,因为攻击者没有第二个身份验证因素。
-
确保网站内容不可被第三方网站嵌入:
- 通过设置
X-Frame-OptionsHTTP 响应头为DENY或SAMEORIGIN,可以防止你的网站内容被第三方网站嵌入为 iframe。这有助于减少“点击劫持”攻击,这是一种特殊类型的 CSRF 攻击。详细参见《设置 X-Frame-Options HTTP 响应头防止点击劫持攻击》
- 通过设置
-
教育用户:
- 用户教育是预防安全威胁的关键部分。确保用户知道不要点击来自不受信任的源的链接,不要打开可疑的邮件附件,并定期更改密码。
在实践中,多层安全防御是最佳的策略。因此,结合使用上述方法可以大大增加应用的安全性。
浙公网安备 33010602011771号