如何限制Spring Security中的登录尝试?

时间:2011-03-18 11:36:23

标签: security login spring-security

Spring Security中是否有一些配置或可用模块来限制登录尝试(理想情况下,我希望在后续失败尝试之间等待时间增加)?如果没有,应该使用哪个API部分?

7 个答案:

答案 0 :(得分:14)

实现AuthenticationFailureHandler,用于更新数据库中的计数/时间。我不会指望使用会话,因为无论如何攻击者都不会发送cookie。

答案 1 :(得分:11)

从Spring 4.2开始annotation based event listeners可用:

@Component
public class AuthenticationEventListener {

    @EventListener
    public void authenticationFailed(AuthenticationFailureBadCredentialsEvent event) {

        String username = (String) event.getAuthentication().getPrincipal();

        // update the failed login count for the user
        // ...
    }

}

答案 2 :(得分:5)

我最近实现了一个类似的功能来监控使用JMX的登录失败。请参阅我对问题Publish JMX notifications in using Spring without NotificationPublisherAware的回答中的代码。身份验证提供程序的身份验证方法的一个方面更新MBean,并使用通知侦听器(该问题中未显示的代码)来阻止用户和IP,发送警报电子邮件,甚至在故障超过阈值时暂停登录。

修改
与我对问题Spring security 3 : Save informations about authentification in database的回答类似,我认为捕获身份验证失败事件(而不是自定义处理程序)并将信息存储在数据库中也将起作用,它也会使代码保持分离。

答案 3 :(得分:5)

正如Rob Winch在http://forum.springsource.org/showthread.php?108640-Login-attempts-Spring-security中所建议的那样,我只是将DaoAuthenticationProvider(也可以使用Ritesh建议的方面完成)来限制登录失败的数量,但你也可以断言前提条件:

public class LimitingDaoAuthenticationProvider extends DaoAuthenticationProvider {
  @Autowired
  private UserService userService;
    @Override
    public Authentication authenticate(Authentication authentication)
        throws AuthenticationException {
      // Could assert pre-conditions here, e.g. rate-limiting
      // and throw a custom AuthenticationException if necessary

      try {
        return super.authenticate(authentication);
      } catch (BadCredentialsException e) {
        // Will throw a custom exception if too many failed logins have occurred
        userService.recordLoginFailure(authentication);
        throw e;
      }
   }
}

在Spring config XML中,只需引用这个bean:

<beans id="authenticationProvider"   
    class="mypackage.LimitingDaoAuthenticationProvider"
    p:userDetailsService-ref="userDetailsService"
    p:passwordEncoder-ref="passwordEncoder"/>

<security:authentication-manager>
    <security:authentication-provider ref="authenticationProvider"/>
</security:authentication-manager>

请注意,我认为可能不会使用依赖于访问AuthenticationException的{​​{1}}或authentication属性(例如实现extraInformation)的解决方案,因为这些属性现已弃用(至少在Spring Security 3.1中)。

答案 4 :(得分:4)

您还可以使用实现ApplicationListener的服务&lt; AuthenticationFailureBadCredentialsEvent&gt;更新数据库中的记录。

参见spring应用程序事件。

答案 5 :(得分:4)

这是我的实施,希望有所帮助。

  1. 创建一个表来存储任何无效的登录尝试。
  2. 如果无效尝试&gt; max allowed,将UserDetail.accountNonLocked设置为false
  3. Spring Security将为您处理“锁定过程”。 (参考AbstractUserDetailsAuthenticationProvider
  4. 最后,扩展DaoAuthenticationProvider,并将逻辑集成在里面。

    @Component("authenticationProvider")
    public class YourAuthenticationProvider extends DaoAuthenticationProvider {
    
    @Autowired
    UserAttemptsDao userAttemptsDao;
    
    @Override
    public Authentication authenticate(Authentication authentication) 
          throws AuthenticationException {
    
      try {
    
        Authentication auth = super.authenticate(authentication);
    
        //if corrent password, reset the user_attempts
        userAttemptsDao.resetFailAttempts(authentication.getName());
    
        return auth;
    
      } catch (BadCredentialsException e) { 
    
        //invalid login, update user_attempts, set attempts+1 
        userAttemptsDao.updateFailAttempts(authentication.getName());
    
        throw e;
    
      } 
    
    }
    
    
    }
    

    有关完整的源代码和实现,请参阅此内容 - Spring Security limit login attempts example

答案 6 :(得分:1)

  1. 创建一个表来存储失败尝试的值ex:user_attempts
  2. 编写自定义事件侦听器

     @Component("authenticationEventListner")
     public class AuthenticationEventListener
     implements AuthenticationEventPublisher
     {
     @Autowired
     UserAttemptsServices userAttemptsService;
    
     @Autowired
     UserService userService;
    
     private static final int MAX_ATTEMPTS = 3;
     static final Logger logger = LoggerFactory.getLogger(AuthenticationEventListener.class);   
    
     @Override
     public void publishAuthenticationSuccess(Authentication authentication) {          
     logger.info("User has been logged in Successfully :" +authentication.getName());       
     userAttemptsService.resetFailAttempts(authentication.getName());       
     }
    
    
     @Override
     public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {               
     logger.info("User Login failed :" +authentication.getName());      
     String username = authentication.getName().toString();
     UserAttempts userAttempt =  userAttemptsService.getUserAttempts(username);
     User userExists = userService.findBySSO(username);
    
     int attempts = 0;
     String error = "";
     String lastAttempted = "";             
     if (userAttempt == null) {     
    
        if(userExists !=null ){                     
        userAttemptsService.insertFailAttempts(username);   }       
      } else {                
          attempts = userAttempt.getAttempts();
          lastAttempted = userAttempt.getLastModified();
        userAttemptsService.updateFailAttempts(username, attempts);         
        if (attempts + 1 >= MAX_ATTEMPTS) {                 
            error = "User account is locked! <br>Username : "
                           + username+ "<br>Last Attempted on : " + lastAttempted;          
        throw new LockedException(error);           
        }                                   
      }
    throw new BadCredentialsException("Invalid User Name and Password");
    
    
    
     }
      }
    
  3. 3.安全配置

             1) @Autowired
             @Qualifier("authenticationEventListner")
             AuthenticationEventListener authenticationEventListner;
    
          2) @Bean
             public AuthenticationEventPublisher authenticationListener() {
             return new AuthenticationEventListener();
             }
          3) @Autowired
             public void 
             configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
             auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
             //configuring custom user details service
             auth.authenticationProvider(authenticationProvider);
             // configuring login success and failure event listener
             auth.authenticationEventPublisher(authenticationEventListner);
             }