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.
No comments:
Post a Comment