Differences between revisions 2 and 3
Revision 2 as of 2009-02-11 16:37:12
Size: 3576
Comment:
Revision 3 as of 2009-09-20 23:20:04
Size: 3576
Editor: localhost
Comment: converted to 1.6 markup
No differences found!

Tapestry5HowToMitigatingLoginAttacks

1. The first step is to create a simple pojo that represents a failed login, we also give it the ability to count failed attempts.

/**
 * @author Peter Stavrinides
 *
 */
public class FailedLogin {

        /** Tracks the number of failed login attempts */
        private int failedLoginCount_ = 0;

        /** The number of times a sleep was invoked */
        private int sleepCount = 0;
        
        /** The delay period (10 minutes in this case)  */
        private int SLEEP_INTERVAL = 600000; 
        
        /** @return the failed login count */
        public int getFailedLoginCount() {
                return failedLoginCount_;
        }
        
        /**
         * A method to provide protection against brute force or dictionary attacks
         * 
         * @throws InterruptedException 
         */
        public void incrementFailedLoginCount() throws InterruptedException {
                //increment the failed login counter
                failedLoginCount_ += 1;
                
                //every 5th failed login we double the sleep period 
                if(failedLoginCount_ == 5){
                        sleepCount +=1; failedLoginCount_ = 0;
                        Logger.getLogger(getClass()).warn(
                                        "Multiple failed login attempts setting sleep interval: "
                                                        + SLEEP_INTERVAL);
                        Thread.sleep(SLEEP_INTERVAL);
                        SLEEP_INTERVAL = (SLEEP_INTERVAL * 2);
                }
        } 
        
        /**
         * @throws InterruptedException
         */
        public FailedLogin() throws InterruptedException{
                incrementFailedLoginCount();
        }
        
}

2. A Tapestry Singleton service to store failed login attempts

public class FailedLoginTracker {
        
        /** A map to track failed logins by IP */
        private static ConcurrentHashMap<String, FailedLogin> failedLogins_ = new ConcurrentHashMap<String, FailedLogin>();
        
        public void setFailedLogin(String ipAddress) throws InterruptedException{
                FailedLogin login = null;
                if(failedLogins_.containsKey(ipAddress)){
                        login  = failedLogins_.get(ipAddress);
                        login.incrementFailedLoginCount();
                }else{
                        //construction ensures increment by 1
                        login = new FailedLogin();
                }
                failedLogins_.put(ipAddress, login);
        }
}

3. lastly add a simple binding in AppModule, a Singleton is the default scope so we only require this:

binder.bind(FailedLoginTracker.class)

4. I have tried to keep the example above as simple as possible, but there are a number of enhancements that one could recommend, the most obvious being more intelligent tracking options other than just the IP, as well as the following modification, which ensures that the FailedLogin object expires (resetting itself) once its 'time to live' passes. The following code is untested therefore omitted from step 1.

        public void incrementFailedLoginCount() throws InterruptedException {
                
                if(expireTime_ != null){
                        Date now = new Date();
                        long diff = now.getTime() - expireTime_.getTime();
                        int hours = (int) (Math.floor(diff / 1000 / 60 / 60));
                        //this object has expired so 
                        if (hours >= TIME_TO_LIVE){
                                sleepCount = 0;
                                failedLoginCount_ = 0;
                        }
                } 
                
                failedLoginCount_ += 1;
                if(failedLoginCount_ == 5){
                        sleepCount +=1; failedLoginCount_ = 0;
                        Logger.getLogger(getClass()).warn(
                                        "Multiple failed login attempts setting sleep interval: "
                                                        + SLEEP_INTERVAL);
                        Thread.sleep(SLEEP_INTERVAL);
                        SLEEP_INTERVAL = (SLEEP_INTERVAL * 2);
                }
                
                //set the expires time
                Calendar ts = Calendar.getInstance();
                ts.add(Calendar.HOUR, 2);
                expireTime_ = new Date(ts.getTimeInMillis());
                System.out.println(expireTime_);
        } 

Peter_Stavrinides (last edited 2009-09-20 23:20:04 by localhost)