My web applications security is handled by Spring Security 3.02 but I can't find any out of the box support for Brute Force Detection.
I would like to implement some application level BFD protection. For example by storing failed login attempt per user in the database (JPA). The attacked user accounts could then get a lockout period or a forced account re-activation by e-mail.
What's the best way to implement this with Spring Security? Does any body have example code or best practices on this?
It's not that hard to roll your own BFD. As in Spring Security 3.0 you can simply add Application listeners (thanks Stephen C for pointing me in the correct direction).
This listener will be called when authentication failures appear:
@Component
public class AuthenticationFailureListener
implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
@Autowired
private UserDao userDao;
public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent ev) {
String username = ev.getAuthentication().getName();
User user = userDao.find("name", username);
if (user != null) { // only for existing users
user.reportLoginFailure();
userDao.commit();
}
}
}
Each authentication failure will now inform the user. The user for example increments an authentication failure counter and deactivates it self when a certain threshold is reached.
When a user is correctly authenticated the below listener will inform the user (who for example can reset it’s authentication failure counters):
@Component
public class AuthenticationSuccessEventListener
implements ApplicationListener<AuthenticationSuccessEvent>{
@Autowired
private UserDao userDao;
public void onApplicationEvent(AuthenticationSuccessEvent event) {
String username = event.getAuthentication().getName();
User user = userDao.find("name", username);
user.reportLoginOK();
userDao.commit();
}
}
The above listeners will not need additional XML configuration and are picked up automatically by Spring (if they are in Spring component-scan package).
Depending on you transaction configuration this solution could miss some failed login counts if they happen near simultaneously. This can be prevented if you update the counter with a single UPDATE query instead of loading the user and then save the changes.
Above listeners can also be extended to detect other BDF patterns, for example a single IP that is doing a scan on lot’s of (random) user names.