我正在研究Spring Web应用程序,我需要避免登录页面上的exps csrf令牌问题,因为如果用户等待太长时间并且尝试只登录一种解决csrf问题的方法是重新加载页面并尝试再次登录。但它不是用户友好的,我想避免这种情况。
第一个问题:一般情况下是否可能(通过春季安全3.2.4)?没有禁用csrf。
我尝试使用security =“none”用于登录页面和spring seciruty“login_check”,但是它没有工作,我得到无限重定向或者我得到错误,没有映射为url“myhost / login_check”。
第二个问题:我该怎么办?
推荐解决方案
我会说你不应该在生产站点上禁用csrf令牌。您可以使会话(因此csrf令牌)持续更长时间(但通常不应持续超过一天,特别是对于未登录的用户,因为它是DOS向量),但真正的解决方案可能是自动刷新csrf令牌过期时的登录页面。你可以用一个
<META HTTP-EQUIV="REFRESH" CONTENT="csrf_timeout_in_seconds">
在您的登录页面标题中。如果用户让登录页面停留数小时,则不应该打扰他刷新页面。
二解决方案
一个可能的解决方案,它不需要你实际存储会话但允许无限超时是你可以从会话ID和服务器端秘密生成你的csrf令牌:
csrf = hash(sessionid+secret)
但请注意,您需要真正挖掘和覆盖spring-security内部机制,即:
- 如果请求到达并且不存在此类会话,则即时重新创建匿名会话
- 从会话ID中动态重新创建csrf令牌
并选择一种非常安全的哈希算法,最好是sha-512。
第三种方案
你可以有一个小的javascript定期调用服务器上的无操作页面(就在会话超时之前),从而扩展你的会话。仅当浏览器一直处于打开状态时,这会导致无限会话超时,因此可以减轻DOS方面的负担。
好的,最后一个解决方案
您可以更改CSRF令牌检查代码,并为登录页面禁用它。这实际上是第二个解决方案的同义词,但是特定于登录页面,通常不适用于所有匿名会话。
你可以这样做,例如通过在HttpSecurity中设置自定义RequestMatcher:
http.csrf().requireCsrfProtectionMatcher(new MyCsrfRequestMatcher());
...
class MyCsrfRequestMatcher implements RequestMatcher {
@Override
public boolean matches(HttpServletRequest request) {
return !request.getServletPath().equals("/login");
}
}
推荐解决方案
我会说你不应该在生产站点上禁用csrf令牌。您可以使会话(因此csrf令牌)持续更长时间(但通常不应持续超过一天,特别是对于未登录的用户,因为它是DOS向量),但真正的解决方案可能是自动刷新csrf令牌过期时的登录页面。你可以用一个
<META HTTP-EQUIV="REFRESH" CONTENT="csrf_timeout_in_seconds">
在您的登录页面标题中。如果用户让登录页面停留数小时,则不应该打扰他刷新页面。
二解决方案
一个可能的解决方案,它不需要你实际存储会话但允许无限超时是你可以从会话ID和服务器端秘密生成你的csrf令牌:
csrf = hash(sessionid+secret)
但请注意,您需要真正挖掘和覆盖spring-security内部机制,即:
- 如果请求到达并且不存在此类会话,则即时重新创建匿名会话
- 从会话ID中动态重新创建csrf令牌
并选择一种非常安全的哈希算法,最好是sha-512。
第三种方案
你可以有一个小的javascript定期调用服务器上的无操作页面(就在会话超时之前),从而扩展你的会话。仅当浏览器一直处于打开状态时,这会导致无限会话超时,因此可以减轻DOS方面的负担。
好的,最后一个解决方案
您可以更改CSRF令牌检查代码,并为登录页面禁用它。这实际上是第二个解决方案的同义词,但是特定于登录页面,通常不适用于所有匿名会话。
你可以这样做,例如通过在HttpSecurity中设置自定义RequestMatcher:
http.csrf().requireCsrfProtectionMatcher(new MyCsrfRequestMatcher());
...
class MyCsrfRequestMatcher implements RequestMatcher {
@Override
public boolean matches(HttpServletRequest request) {
return !request.getServletPath().equals("/login");
}
}
默认情况下,另一个选项是没有为会话设置超时,然后,当用户通过身份验证时,将超时更改为您想要的任何内容。您可以看到如何执行此操作的示例 这里。
您还可以使CSRF保护依赖于cookie而非服务器端会话状态。 Spring Security完全支持这一点。
CookieCsrfTokenRepository
如果您的cookie过期,您将只收到超时。这很好地扩展,因为它基本上是无状态的(从服务器的角度来看)。
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
安德鲁