Daniel is a business and technical systems analyst with a background in IT security and software development. He has six years experience in the IT security field, including published academic research. His main areas of expertise include software assurance, network security, and authentication. In addition to security, Daniel has a software development background in languages such as Java, Perl, SQL, and PHP. He also has 14 years experience working with and administering various versions of Linux and related open-source software.
Secure Development - Access Control
Mar 20 2010
Most people are familiar with authentication, the process of proving who you are (usually with a username and password). Access control sounds very similar, but there is a subtle difference: access control refers to the permissions assigned to an authenticated person or entity. In other words, access control first requires successful authentication, and then it can use the identity of the logged-in user to determine to which resources he has access.
It is also possible to enforce access control without any authentication taking place, which in most cases will revert to limited/guest access. An example of this is an e-commerce application that allows users to shop without logging in. Users are only prompted to log in when they are ready to check out, which then unlocks the other features of the application (access to their stored user data, the ability to pay, etc.). As an aside, it is important in this scenario to always generate a new session ID when a user logs in to prevent a "session fixation attack" (more on that in next week's post).
Incorrectly implemented access control can have some serious security implications. Even a highly secure three-factor authentication (passcode, token, and biometrics) is useless without proper access control: a user could potentially access other users' data or administrative functions. Some common examples of broken access control are:
- Insecure ID’s (guessable/sequential order numbers, etc.)
- Forced browsing past access control checks (only the first page is checked)
- Path traversal, incorrect file permissions
- Client-side caching (pages may still reload after session expires)
In the insecure ID scenario, let's assume that a web application allows customers to retrieve their order history by invoice number. The following JSP code is being used to perform the access control check:
if(session.getAttribute("authenticated").equals("true")) {
app.getInvoice(request.getParameter("invoiceNumber"));
}
The problem here is that the authentication state of the session is used as a simple yes/no check for user access to all invoices. The invoiceNumber parameter is controlled by the user (submitted as part of the GET/POST request for this JSP), so it can contain anything. As long as the user is authenticated to his own account, he can access any valid invoice number that exists in the system. To prevent this problem, the application needs to keep track of all invoices belonging to a particular user and only allow access if the invoice number being requested belongs to the currently logged-in user.
In general, you can use the following techniques for reducing the risk of broken access control:
- Use declarative access control: Declarative security works by defining all permissions in a single configuration file or database. This is a vast improvement over programmatic security, which embeds the application's security logic in the code itself. There are many advantages, including easy maintenance (changes only need to be made in one place), less chance for errors (forgetting to paste in the code for the access control check), and readability (it's much easier to audit a single configuration file rather than scouring hundreds of source files).
- Leverage existing access control frameworks: For example, Spring Security provides a comprehensive toolkit for web application access control. Using a framework has two main advantages: 1) it's declarative instead of programmatic (see above) and 2) it provides centralized access control without the need to insert or change specific code for each access control check
- Check permissions with every request: Don't rely on a previous access control check, perform a fresh check each time. If you're using a declarative model, this tip usually doesn't apply because each request is checked by default.
- Client-side caching: Use the "no-cache" HTTP header or meta tag to prevent client-side caching on most browsers.
- File permissions: Use the server's filesystem permissions to properly secure the files in the web server root. This also helps protect against information leaks and file-upload attacks.
Proper access control deserves as much attention as authentication, though this often doesn't happen in practice. By using the tips above, you can ensure that your users are not only who they say they are, but that they're not accessing application objects or features that don't belong to them.
Next week, we'll talk about the other side of the equation, proper authentication and session management. Entire books have been written on authentication, but we will cover the basics that are relevant to web applications.
© 2011 CapTech Ventures, Inc. All Rights Reserved. Legal Notices.