Saturday, April 30, 2016

App Layer Intrusion Detection



Most, if not all, organizations have a policy that states after so many failed login attempts the user’s account shall be locked out.  Why is this?  Over many years it has been decided this is a security event that needs to be responded to immediately and in an automated fashion.  It’s simple for the person developing the authentication piece of the code to track how many consecutive failed login attempts a user has and then lockout the account once the failed login attempts have exceeded some threshold.  Imagine if all the application did was log this event and wait for a member of the information security staff to review the incident.  By this time an attacker could have brute forced their way into the account.  It makes sense to automate this response since there is a well-defined decision tree that dictates what should happen.  But why is this the only security event where there is any prescriptive guidance laying out what action the application should take?

I have been digging into app layer intrusion detection over the last couple of weeks.  After reading about this concept in Jim Manico’s book Iron-Clad Java: Building Secure Web Applications and looking into OWASP’s AppSensor project I wonder why we aren’t building more requirements around detecting intrusion attempts into our applications.  The application layer is a perfect place to not only detect application attacks but also to respond to these attacks.  The application has so much information about what is happening in its ecosystem but we don’t seem to be taking advantage of this benefit.  

Building in functionality to detect and respond to security events sounds like a lot of extra work but it’s really not.  Let’s take an authorization function for a banking application as an example.  Here’s some pseudocode of what a function might look like where a user is trying to access their bank account:

if(user.isAuthorized){
               //Allow user to proceed
else{
               //log the event
               //present an error message to the user
}

Does anyone else see what I see?  We have identified a potential security event.  Assuming the UI does not allow the user to manually enter their account number there is really no way for a user to accidentally access another user’s account without manipulating the application.  For failed login attempts we track the number of consecutive failed login attempts and then lockout the user after a threshold has been passed.  Let’s do the same thing with failed authorization attempts.  Because the security check has already been written all we need to do is write a few extra lines in the else statement to track how many failed authorization attempts there have been and then lockout the user’s account once that threshold has been crossed.

One of the questions I often hear when I propose security requirements is how will this affect the user’s experience?  That’s a great question.  Sometimes I flip it around and ask the developer or business owner how the user experience will be impacted if these security requirements aren’t implemented and a user’s account gets hacked.  With the banking example above, the user experience won’t be impacted all that much.  If the user attempts to access a bank account they are not authorized to view they will see an error message.  All we are doing is locking out the account after so many attempts.  In this case I would add the requirement that the user has to call the help desk to unlock their account.  This will give the help desk time to review the incident and alert the user there was a security incident and remind the user that trying to access someone else’s bank account is against the terms of service.  

The above pseudocode shows that our application is protected against unauthorized attempts to access accounts that don’t belong to the user.  By locking out the account we are not only alerting the user they are doing something wrong but we are preventing the user from moving on to attempting other attacks such as SQL injection.  Let’s say a user has logged into a banking application and decided to run a scan against the application.  If we have checks to identify various attacks such as SQL injection, XSS, CSRF, etc. we have all of the information we need to stop the user from proceeding any further from doing a scan.  We might have a XSS vulnerability we don’t know about but because we are protected against SQLi and we detected multiple SQLi attempts we have locked out the user from proceeding further to scan for XSS vulnerabilities.  

Up to this point I have dealt with an authenticated user trying to perform attacks against an application.  It is much easier to take action when we know who is performing the attacks.  We can still be responsive when it comes to unauthenticated attacks but it takes a lot more work.  A lot more analysis of the attack has to be performed.  But in this case the security events should still be logged and raised to the incident response team.  The application should also present error messages in such a way that the application informs the user that a security event was detected and the user’s actions are being logged and actively monitored.  

In all of this we have been responsive towards a potential attack.  We could be less forceful and log everything and hope that someone on the incident response team sees the activity and takes action.  This is being reactive towards a security event rather than being responsive.  The IR team might take days to see this event and by then it’s too late.  Somehow along the way it has become mandatory to lockout accounts after a certain number of failed login attempts.  I would like to see other events such as failed authorization attempts, SQL injection attempts, etc. become mandatory events that are cause for user’s having their accounts locked out.  Let’s automate some of these responses rather than relying on an overworked IR team to detect and react to these events.