4 Common Mistakes Developers Make When Implementing Authentication and Session Management
Authentication, authorization and session management are obviously key elements in securing a web application. With proper planning, these areas are actually comparably easy to get right - ideally, developers can simply make use of existing libraries and web server facilities. However, authorization and session management issues are often found in more complex apps, especially when security was not considered during the design process. In the following list I describe some types of issues we encounter often in code reviews and pen tests.
Missing or Weak Password Policies
We all have seen it in the movies: The protagonist “hacks into the system" in mere seconds, hand-guessing the correct password (usually it's something super-obvious like the name of the antagonists long-deceased child). As cliched as it might seem, it is unfortunately close to reality in many cases, because password policies are too lax in 90% of web applications.
I define the "Golden Rule of Password Policies" as follows:
For a given password policy, there are at least some users who choose the weakest possible password allowed by the policy.
Let’s say the policy asks for 10 characters with at least one upper/lower case letter, one digit and one special char. In a system with 1,000 users following this policy, there is an almost 100% chance that there will be at least one user with the the password “Password1!” - more likely many of them. This is why in cases where we know the password policy and have a list of usernames, we can often guess at least some of the accounts, even if login attempts are throttled or blocked after a few tries (as a side note, you also shouldn’t disclose all the usernames).
For better password security, implement a password complexity check that enforces a minimum amount of randomness in the passwords. There are various libraries that offer this functionality. Granted, this is annoying for the users, and might be too much to ask in some environments.
Failing to Consistently Enforce Authorization on the Server
It's not uncommon for modern "Enterprise" applications to have a whole lot of components on the client and server interacting with each other. A single application might incorporate servlets, JSPs, Struts2 actions, and other interfaces, all doing their bidding in the context of a user's session. It can be difficult to enforce authorization consistently throughout all these components.
As an example, in a recent project I encountered an AJAX-enabled administrative interface that executed actions via Direct Web Remoting (DWR). While the admin console itself did properly check the user’s role (and showed only the appropriate AJAX-enabled buttons for the role), there were no server-side role checks on the AJAX request. As a result, any authenticated user could execute administrative actions simply by sending the correct requests directly to the DWR servlet.
As an important rule, user roles must be enforced on all endpoints. The larger the application, the more careful planning is necessary to get the security architecture right.
While an authentication system that utilizes two factors is twice as secure, it's also twice as error prone (OK, maybe "twice as secure" is not exactly correct but you get the point). 2FA makes it necessary to track additional state information, i.e. whether the uses has provided the second factor, whether a certain action can be executed or not given the users’ authentication level, and so on. For some reason this seems difficult to get right, and we often see cases where 2FA can be bypassed, e.g. by accessing actions out of sequence.
In large web applications, such as web banking or online trading systems, the authentication flow can become quite complex. Careful architecture design is very important in these cases - it is difficult to tack 2FA onto an already complicated authorization system, especially when the regular session management is already confusing.
Re-Inventing the Wheel
This is valid for most areas but is worth repeating here, because it's especially true when session management is concerned. Every time developers decide to implement a proprietary session management system, it ends in a disaster. There are just too many things that can go wrong.
Most web languages and frameworks provide perfectly fine and proven components for handling authentication and authorization. Examples are standard implementations of the Java Servlet HTTPSession Interface and PHP sessions. Session management should always be based on these existing components. If the existing functionality is not enough, additional functionality can be layered on top of these basic components. You should be fine as long as you use the proven methods and follow best practices.
Disclaimer: This is by no means a complete list! If you have any of your own experiences to share, please let us know in the comments.
About the Author
Bernhard Mueller is a full-stack hacker, security researcher, and winner of BlackHat's Pwnie Award.
Follow him on Twitter: @muellerberndt