Are there any features specifically in Spring 3.0 MVC that would help implementing detection of a brute force attack on the authentication/login page of a web app?
Long-proven practice is to introduce a random but sizable delay if authentication has failed.
This way legitimate users will log on right away, but an attacker will spend 500ms-1s per try, which makes the whole brute-force idea impractical (will take forever).
Occasional failed login by legitimate users will cause them only a minor delay and will go unnoticed.
If you need to be notified on repeated failed logins, you need to implement a report printing number of consequential failed logins per user, order by that number desc limit 100.
P.S. Here is a post explaining how to get notified on login attempt. Following the same approach one can introduce a delay, I believe.
It is possible by some configurations and coding in Spring security.
By the way, I do not suggest to make some delay in front of suspicious invalid login trials. You may make some delay to respond to a suspicious login attempt but this delay costs you to suspend a thread for a while in your application. This may provide DoS or DDoS attack on your system if there are high amount of invalid logins happen simultaneously to your application.
The better approach is to make a fast response to a suspicious invalid login but at the same time to suspend the user account by which the user is trying to login. In this way, brute force attack avoidance does not lead to provision of Dos or DDoS attack.
Nevertheless, suspension of user account would also provide a way for DoS attack, for it may lead to failure in delivery of service to real user. But, correct security scenarios would be helpful in these cases. For example, if a brute force attack is detected, you may:
All of this depends to your domain and service scenarios. As an example, you may implement your own UserDetailsService and detect brute force attack in this implementation.
To implement the last scenario by Spring Security, the following code declares an authentication-manager which is passed a custom UserDetailsService which type is JdbcDaoImpl here (Note that package names and queries must be modified to your own package and data model).
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="CustomUserDetailsService" />
</authentication-manager>
<!--
This bean is to provide jdbc-user-service.
Also, it provides a way to avoid BFD along with AuthenticationFailureListener
-->
<bean id="CustomUserDetailsService" class="com.example.CustomUserDetailsService">
<property name="dataSource" ref="dataSource" />
<property name="usersByUsernameQuery" value="SELECT user_client.user_name, user_client.password, user.is_active
FROM user_client INNER JOIN user ON user_client.fk_user = user.ID
WHERE user_client.user_name=? "/>
<property name="authoritiesByUsernameQuery" value="SELECT user_client.user_name, CONCAT('ROLE_',user_client.client_id)
FROM user_client WHERE user_client.user_name=? "/>
</bean>
The CustomUserDetailsService detects if there is a brute force attack happening or not, along with AuthenticationFailureListener that I discuss soon. FailedLoginCacheManager is a ehcache wrapper that maintains the failed logins (usernames) with their relative failed amounts. The cache is set with a proper timeToIdleSeconds to make the account suspension temporary.
public class CustomUserDetailsService extends JdbcDaoImpl {
@Autowired
private FailedLoginCacheManager cacheManager;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (cacheManager.isBruteForceAttackLogin(username)) {
//throw some security exception
...
}
return super.loadUserByUsername(username);
}
}
Also, a ApplicationListener is implemented to detect failed login attempts and preserve them inside the ehcache.
@Component public class AuthenticationFailureListener implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
@Autowired
private FailedLoginCacheManager cacheManager;
@Override
public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) event.getSource();
String userName = token.getPrincipal().toString();
cacheManager.updateLoginFailureStatus(userName);
}}
There is no need to discuss more about FailedLoginCacheManager service but two main methods that are discussed here could be implemented like the following methods:
public void updateLoginFailureStatus(String userName) {
Cache cache = manager.getCache(CACHE_NAME);
Element element = cache.get(userName);
if (isValid(element)) {
int failureCount = (Integer)element.getObjectValue();
cache.remove(userName);
cache.put(new Element(userName, ++failureCount));
} else {
cache.put(new Element(userName, 1));
}
}
public boolean isBruteForceAttackLogin(String username) {
Cache cache = manager.getCache(CACHE_NAME);
Element element = cache.get(username);
if (isValid(element)) {
int failureCount = (Integer)element.getObjectValue();
return failureCount >= 3;
} else {
return false;
}
}
Surprisingly, I couldn't find anything in the reference docs for either Spring MVC or Spring Security.
I did, however, find this 3 year old tutorial that describes how it can be done using Splunk.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With