问题 CSRF令牌在登录期间到期


我正在研究Spring Web应用程序,我需要避免登录页面上的exps csrf令牌问题,因为如果用户等待太长时间并且尝试只登录一种解决csrf问题的方法是重新加载页面并尝试再次登录。但它不是用户友好的,我想避免这种情况。

第一个问题:一般情况下是否可能(通过春季安全3.2.4)?没有禁用csrf。

我尝试使用security =“none”用于登录页面和spring seciruty“login_check”,但是它没有工作,我得到无限重定向或者我得到错误,没有映射为url“myhost / login_check”。

第二个问题:我该怎么办?


10310
2017-12-16 09:22


起源



答案:


推荐解决方案

我会说你不应该在生产站点上禁用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");
    }
}

16
2017-12-16 09:28



它与重新加载页面的解决方案相同,可以工作,但不是用户友好的。 - Vartlok
但用户没有必要 手动 重新加载页面。很可能用户甚至不会注意到页面被重新加载,如果他没有触摸页面几个小时,所以我认为这不是问题。 - P.Péter
如果您的会话永远持续下去,那将是DOS攻击向量(因为您需要内存/磁盘来存储这些会话和csrf令牌)。但是你可以做到这一点,如果停机时间很小,对你的用户来说比在后台重新加载更不方便...... - P.Péter
我想会话的无限超时(或非常长)是最糟糕的解决方案。但重装页面并不完美。 - Vartlok
但是如果你没有无限超时,不要更新会话,也不要禁用csrf,那么在会话超时后如何获得有效的CSRF令牌呢? - P.Péter


答案:


推荐解决方案

我会说你不应该在生产站点上禁用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");
    }
}

16
2017-12-16 09:28



它与重新加载页面的解决方案相同,可以工作,但不是用户友好的。 - Vartlok
但用户没有必要 手动 重新加载页面。很可能用户甚至不会注意到页面被重新加载,如果他没有触摸页面几个小时,所以我认为这不是问题。 - P.Péter
如果您的会话永远持续下去,那将是DOS攻击向量(因为您需要内存/磁盘来存储这些会话和csrf令牌)。但是你可以做到这一点,如果停机时间很小,对你的用户来说比在后台重新加载更不方便...... - P.Péter
我想会话的无限超时(或非常长)是最糟糕的解决方案。但重装页面并不完美。 - Vartlok
但是如果你没有无限超时,不要更新会话,也不要禁用csrf,那么在会话超时后如何获得有效的CSRF令牌呢? - P.Péter


默认情况下,另一个选项是没有为会话设置超时,然后,当用户通过身份验证时,将超时更改为您想要的任何内容。您可以看到如何执行此操作的示例 这里


0
2017-12-21 19:32





您还可以使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());
    }
}

安德鲁


0
2018-04-11 15:04



应该补充一点,spring文档将存储在cookie中的csrf令牌称为潜在不安全因此,因此默认情况下会将令牌存储在会话中。看到 docs.spring.io/spring-security/site/docs/current/reference/html/...。 - Rolch2015