Spring官方提供【CSRF攻击】解决方案

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

步入正文

Cookie

cookie是我们常见用来保存用户态信息cookie跟随我们的请求自动携带。在同一域名下的请求cookie总是自动携带。

用户态: 当前登入者的用户信息

以上的特性会导致一个潜在漏洞-CSRF

CSRF

CSRF一般指跨站请求伪造。 跨站请求伪造英语Cross-site request forgery下图举一个例子在这里插入图片描述
危险漏洞出现在步骤四此时网站B请求了网站A又因为cookie的特性会将一二步骤使用的Cookie导致请求成功此时的转账是成功的。
就此出现了CSRF 跨站请求伪造漏洞。

解决方案

Spring 提供了两种机制来防止 CSRF 攻击

  1. 同步器令牌模式
  2. 在会话 Cookie 上指定同一网站属性

这两种保护都要求安全方法是幂等的。

1.同步器令牌模式

防范 CSRF 攻击的主要和最全面的方法是使用同步器令牌模式。 此解决方案是为了确保除了我们的会话 cookie 之外每个 HTTP 请求还需要在 HTTP 请求中存在一个称为 CSRF 令牌的安全随机生成值。

提交 HTTP 请求时服务器必须查找预期的 CSRF 令牌并将其与 HTTP 请求中的实际 CSRF 令牌进行比较。 如果值不匹配则应拒绝 HTTP 请求。

这项工作的关键是实际的CSRF令牌应该在HTTP请求的一部分中浏览器不会自动包含该部分。 例如在 HTTP 参数或 HTTP请求头中要求实际的 CSRF 令牌将防止 CSRF 攻击。 在 cookie 中要求实际的 CSRF 令牌是行不通的因为浏览器会自动将 cookie 包含在 HTTP 请求中。

我们可以放宽期望为每个更新应用程序状态的 HTTP PUTPOSTDELETE请求仅要求实际的 CSRF 令牌。 为此我们的应用程序必须确保安全的 HTTP 方法是幂等的。 这提高了可用性因为我们希望允许从外部网站链接到我们的网站。 此外我们不希望在 HTTP GET 中包含随机令牌因为这可能会导致令牌泄露。

考虑一下使用同步器令牌模式时我们的示例将如何变化。 假设实际的 CSRF 令牌需要位于名为 的 HTTP 参数中。 我们应用程序的转移表单如下所示

2. 同网站属性

防止CSRF攻击的一种新兴方法是在cookie上指定SameSite属性。 服务器可以在设置 Cookie 时指定属性以指示来自外部站点时不应发送 Cookie

具有该属性的 HTTP 响应标头的示例可能如下所示

Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; SameSite=Lax

该属性的有效值为SameSite

  1. Strict指定后来自同一站点的任何请求都包含 cookie。 否则Cookie 不会包含在 HTTP 请求中。
  2. Lax指定后当来自同一站点或请求来自顶级导航且方法幂等时将发送 Cookie。 否则Cookie 不会包含在 HTTP 请求中。

在我们的会话 Cookie 上设置该属性后浏览器会继续发送来自银行网站的请求的 Cookie。 但是浏览器不再发送带有来自邪恶网站的传输请求的cookie。 由于会话不再存在于来自恶意网站的传输请求中因此应用程序受到保护免受CSRF攻击。

另一个明显的考虑因素是为了使属性保护用户浏览器必须支持该属性。 大多数现代浏览器都支持 SameSite 属性。 但是仍在使用的旧版浏览器可能不会。

出于这个原因我们通常建议将该属性用作深度防御而不是针对 CSRF 攻击的唯一保护

何时使用 CSRF 保护

何时应使用 CSRF 保护 我们的建议是对普通用户可以通过浏览器处理的任何请求使用 CSRF 保护。 如果要创建仅由非浏览器客户端使用的服务Frame等嵌套则可能需要禁用 CSRF 保护。

CSRF 保护和 JSON

一个常见的问题是“我需要保护JavaScript发出的JSON请求吗 简短的回答是视情况而定。 但是您必须非常小心因为存在会影响 JSON 请求的 CSRF 漏洞。 例如恶意用户可以使用以下形式使用 JSON 创建 CSRF

<form action="https://bank.example.com/transfer" method="post" enctype="text/plain">
	<input name='{"amount":100,"routingNumber":"evilsRoutingNumber","account":"evilsAccountNumber", "ignore_me":"' value='test"}' type='hidden'>
	<input type="submit"
		value="Win Money!"/>
</form>

这将生成以下 JSON 结构

{ "amount": 100,
"routingNumber": "evilsRoutingNumber",
"account": "evilsAccountNumber",
"ignore_me": "=test"
}

如果应用程序未验证header则会暴露在此攻击中。 根据设置的不同验证内容类型的Spring MVC应用程序仍可以通过将URL后缀更新为以 结尾来利用如下所示Content-Type.json

<form action="https://bank.example.com/transfer.json" method="post" enctype="text/plain">
	<input name='{"amount":100,"routingNumber":"evilsRoutingNumber","account":"evilsAccountNumber", "ignore_me":"' value='test"}' type='hidden'>
	<input type="submit"
		value="Win Money!"/>
</form> 

CSRF 和无状态浏览器应用程序

如果我的应用程序是无状态的怎么办 这并不一定意味着您受到保护。 事实上如果用户不需要在 Web 浏览器中对给定的请求执行任何操作他们可能仍然容易受到 CSRF 攻击。

例如考虑一个应用程序它使用自定义 cookie其中包含用于身份验证的所有状态而不是 JSESSIONID。 当进行 CSRF 攻击时自定义 cookie 与请求一起发送的方式与前面示例中发送 JSESSIONID cookie 的方式相同。 此应用程序容易受到 CSRF 攻击。

使用基本身份验证的应用程序也容易受到 CSRF 攻击。 该应用程序容易受到攻击因为浏览器会自动在任何请求中包含用户名和密码其方式与上一个示例中发送 JSESSIONID cookie 的方式相同。

CSRF 注意事项

在实施针对 CSRF 攻击的保护时需要考虑一些特殊注意事项。

登录

为了防止伪造登录请求应保护登录 HTTP 请求免受 CSRF 攻击。 防止伪造登录请求是必要的以便恶意用户无法读取受害者的敏感信息。 攻击的执行方式如下

伪造登录请求攻击者可能会伪造请求使用攻击者的凭据将受害者登录到目标网站;这称为登录 CSRF。登录CSRF使各种新颖的攻击成为可能;例如攻击者稍后可以使用其合法凭据登录站点并查看私人信息例如已保存在帐户中的活动历史记录。这种攻击已经针对谷歌[12]和雅虎进行了演示。[注13]

  1. 恶意用户使用恶意用户的凭据执行 CSRF 登录。 受害者现在被验证为恶意用户。
  2. 然后恶意用户诱骗受害者访问受感染的网站并输入敏感信息。
  3. 该信息与恶意用户的帐户相关联因此恶意用户可以使用自己的凭据登录并查看受害者的敏感信息。

确保登录 HTTP 请求免受 CSRF 攻击的一个可能的复杂性是用户可能会遇到会话超时从而导致请求被拒绝。 会话超时对于不希望需要会话才能登录的用户来说令人惊讶。 有关更多信息请参阅 CSRF 和会话超时。

注销

为了防止伪造注销请求应保护注销 HTTP 请求免受 CSRF 攻击。 防止伪造注销请求是必要的以便恶意用户无法读取受害者的敏感信息。 有关攻击的详细信息请参阅此博客文章

确保注销 HTTP 请求免受 CSRF 攻击的一个可能的复杂性是用户可能会遇到导致请求被拒绝的会话超时。 会话超时对于不希望有会话注销的用户来说令人惊讶。 有关更多信息请参阅 CSRF 和会话超时。

CSRF 和会话超时

通常预期的CSRF令牌存储在会话中。 这意味着一旦会话过期服务器就找不到预期的 CSRF 令牌并拒绝 HTTP 请求。 有许多选项每个选项都有权衡来解决超时问题

  1. 缓解超时的最佳方法是使用 JavaScript 在表单提交时请求 CSRF 令牌。 然后使用CSRF令牌更新表单并提交。
  2. 另一种选择是使用一些 JavaScript让用户知道他们的会话即将过期。 用户可以单击按钮以继续并刷新会话。
  3. 最后预期的CSRF令牌可以存储在cookie中。 这让预期的 CSRF 令牌比会话更长久。

有人可能会问为什么预期的CSRF令牌默认情况下不存储在cookie中。 这是因为存在已知的漏洞其中标头例如指定 cookie可由另一个域设置。 这与Ruby on Rails在标头X-Request-With存在时不再跳过CSRF检查的原因相同。 有关如何执行漏洞利用的详细信息请参阅此 webappsec.org 线程。 另一个缺点是通过删除状态即超时您将失去在令牌遭到入侵时强制使令牌无效的能力。

分段文件上传

保护分段请求文件上传免受 CSRF 攻击会导致先有鸡还是先有蛋的问题。 为了防止CSRF攻击的发生必须读取HTTP请求的正文以获取实际的CSRF令牌。 但是读取正文意味着文件已上传这意味着外部站点可以上传文件。

对多部分/表单数据使用 CSRF 保护有两种选择

  1. 将CSRF令牌放入正文
  2. 将 CSRF 令牌放在 URL 中

每个选项都有其权衡取舍。

在将 Spring Security 的 CSRF 保护与分段文件上传集成之前您应该首先确保可以在没有 CSRF 保护的情况下进行上传。 有关在 Spring 中使用多部分表单的更多信息请参见 1.1.11。Spring 参考的多部分解析器部分MultipartFilter Javadoc

将CSRF令牌放入正文

第一个选项是在请求正文中包含实际的 CSRF 令牌。 通过将 CSRF 令牌放在正文中可以在执行授权之前读取正文。 这意味着任何人都可以在您的服务器上放置临时文件。 但是只有授权用户才能提交由您的应用程序处理的文件。 通常这是推荐的方法因为临时文件上载对大多数服务器的影响可以忽略不计。

在 URL 中包含 CSRF 令牌

如果不允许未经授权的用户上传临时文件另一种方法是在表单的操作属性中包含预期的 CSRF 令牌作为查询参数。 此方法的缺点是查询参数可能会泄漏。 更一般地说最佳做法是将敏感数据放在正文或标头中以确保它不会泄露。 您可以在 RFC 2616 第 15.1.3 节 URI 中的敏感信息编码中找到其他信息。

隐藏的HttpMethodFilter
某些应用程序可以使用表单参数来重写 HTTP 方法。 例如以下表单可以将 HTTP 方法视为 而不是 .deletepost

CSRF 隐藏的 HTTP 方法表单

<form action="/process"
	method="post">
	<!-- ... -->
	<input type="hidden"
		name="_method"
		value="delete"/>
</form>

重写 HTTP 方法发生在筛选器中。 该过滤器必须放在 Spring Security 的支持之前。 请注意覆盖只发生在 上因此这实际上不太可能导致任何实际问题。 但是最佳做法仍然是确保将其放置在 Spring 安全性的过滤器之前。post

本文

主要来源
https://docs.spring.io/spring-security/reference/features/exploits/csrf.html#csrf-when-stateless
https://docs.spring.io/spring-security/reference/features/exploits/csrf.html#csrf-when-stateless
https://docs.spring.io/spring-security/reference/features/exploits/csrf.html#csrf-when-stateless

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring