Ok, well now we’ve been through all the issues listed in the 2007 version of the Top Ten. The new 2010 version is very similar with a couple discrepancies. I may follow up on those couple of issues at a later time. Hopefully you’ve seen through all the articles in this series that ESAPI (specifically the Java version was used) was built to deal with quite a few real security issues that developers face today. This series has shown that ESAPI can be used in almost every instance to either partially or completely remediate a specific issue, and to do it properly. The ESAPI community is thriving, and good things are coming out frequently. New implementations of some controls are showing up. New people are joining. New issues are being tackled. Get involved with this community and make it better. Use the outstanding controls this group has kindly given away, and offer some of your own.
Hopefully this series has been helpful to you in moving closer to secure J2EE development by exposing you to ESAPI and all it has to offer. I’ll be moving on to different topics in the future. Hope you enjoyed this one!
As a reference, all the articles from the series are listed below for easy access.
——————
Part 0: The OWASP Top Ten and ESAPI
Part 1: The OWASP Top Ten and ESAPI – Part 1 – Cross Site Scripting (XSS)
Part 2: The OWASP Top Ten and ESAPI – Part 2 – Injection Flaws
Part 3: The OWASP Top Ten and ESAPI – Part 3 – Malicious File Execution
Part 4: The OWASP Top Ten and ESAPI – Part 4 – Insecure Direct Object Reference
Part 5: The OWASP Top Ten and ESAPI – Part 5 – Cross Site Request Forgery (CSRF)
Part 6: The OWASP Top Ten and ESAPI – Part 6 – Information Leakage and Improper Error Handling
Part 7: The OWASP Top Ten and ESAPI – Part 7 – Broken Authentication and Session Management
Part 8: The OWASP Top Ten and ESAPI – Part 8 – Insecure Cryptographic Storage
Part 9: The OWASP Top Ten and ESAPI – Part 9 – Insecure Communications
Part 10: The OWASP Top Ten and ESAPI – Part 10 – Failure to Restrict URL Access
——————
As a final note, I’d like to make a special request. If you have any requests for something you’d like to see here, an article on a specific topic involving J2EE web security, feel free to comment here or send me an email. My direct contact info is listed on the About page.
This article will describe how to protect your J2EE application from Failure to Restrict URL Access attacks using ESAPI and other techniques. As with all of the detail articles in this series, if you need a refresher on OWASP or ESAPI, please see the intro article The OWASP Top Ten and ESAPI.
What does Failure to Restrict URL Access mean? As usual, let’s check in with what OWASP says it is:
“Frequently, the only protection for a URL is that links to that page are not presented to unauthorized users. However, a motivated, skilled, or just plain lucky attacker may be able to find and access these pages, invoke functions, and view data. Security by obscurity is not sufficient to protect sensitive functions and data in an application. Access control checks must be performed before a request to a sensitive function is granted, which ensures that the user is authorized to access that function.” [from here]
Wow, what does all that mean? Well, the Failure to Restrict URL Access (hereafter referred to as URL authz) is simply a failure of performing a subset of authorization. Authorization is a large topic, with many volumes already written on it, but a short overview here will be helpful to the discussion. Authorization is typically described as ensuring a user has access to something, either a business function, data or both. Here’s a simple example:
User Mary makes a request to delete account id 375.
This statement requires authorization verification. Before we look at authorization, it is assumed that the authentication has already been performed, hence Mary is verified to be Mary. Now for the authorization, we must validate that Mary has access to the “delete account” business function and that she can perform that action for account id 375.
There are many, many ways to perform authorization, some better than others. There are 3 basic issues that crop up when dealing with authorization for the developer: security, granularity and maintainability.
The security piece is foundational – is the implementation secure. If a user requests a resource, the authorization should:
1. execute on every configured request (which should be all requests, except possibly static resources available to everyone)
2. allow access if the user has rights to the function and/or data
3. deny access if the user does not have rights to the function and/or data
The granularity piece has to do with flexibility in specifying restrictions about the authorization constraints. Using our example above, the simplest correct authorization would validate 2 things:
1. that Mary has access to the “delete account” function (meaning presumably she could run this function on any data she has access to).
2. that Mary has access to account id 375 (meaning presumably she could run any function she has access to on this data).
A more complex authorization scheme for this same example might provide more granular controls. It may allow Mary to have access to thousands of accounts, and a handful of various functions, but there may be some accounts she has read-only access to, some she can write to, and some she has full access over. Additionally, there may be a limiting feature of time of day, something like Mary is only authorized to perform these functions between 8am – 5pm (normal work hours). Other limits can certainly be thought of as well.
Obviously the second description has more granularity in specifying constraints, but this implementation will also have to be more complex, and more data will have to be captured to provide the matrix of information required to make an authorization decision.
The maintainability piece deals with the complexity of the design, implementation and stored data as mentioned above in the granularity section. The balance between simplicity of implementation and flexibility is an application specific decision. However, some of this complexity can be reduced by using pre-built solutions like ESAPI, as we’ll see shortly.
Ok, now we’ve covered a bit about authorization in general, let’s discuss URL authz in a bit more detail. URL authz is about a user gaining access to a URL that they should / should not have access to. Using the same example above, the request for a business function to delete an account might be a url like:
/myapp/account/delete?id=375
This is how a request is made in a web app, through URL’s. From this request, we know the user is looking to delete an account from the url, and the account id is 375 from the parameter. In order to validate that this is a valid request, we need to make sure that the user should be able to access the delete account URL. There are a couple of locations this could be done: from the referring page, and from the request handling function itself. You must use the latter, and should use the former for user experience. So, if I’m on the view accounts page, and I do NOT have access to delete, I should not even see the link/button for delete – that’s about user experience. However, if my application prevents the link from displaying, but the user were to directly type it in, he would still have access if I didn’t prevent the access from the request handling function as well. This bit of pseudocode will help get the point across:
JSP code
//if user has access to delete
show link to delete page
//else
show nothing
-----------------
in the servlet/action handling the delete request
//get the user performing the request
//get the account id
//if the user has access to delete this data
proceed
//else
throw some error, log issue, possibly respond in some way to attempted "hack"
Both of these checks are important, but the second is vital to protecting the application. Doing the first only is a form of security by obscurity, which almost always provides very little protection. It won’t be long until the user guesses that this url exists, or until he sees another user access it, and then is able to get there.
Ok, so we’ve now described how standard authorization and specifically URL authz works, let’s see a few practical tips and tricks about how to implement it.
1. Think about authorization at the beginning of the application architecture and design if possible. This can make things much simpler down the road. You can come up with a defined naming scheme to follow or any other host of ideas to simplify the task at hand.
2. Always authorize URLs at the time of the request processing (for security), and you should authorize access at the time of providing a link (for uxp).
3. Pen-test if possible – use both automated and manual testing. This can help ensure a decent sampling of urls are not accessible. Even if you can’t do it exhaustively, it will help build confidence in your solution if a subset works. If you can exhaustively test – all the better.
4. Remember included files – these can be forgotten sometimes, but these can often be accessed.
5. Put all your UI files under /WEB-INF, and use a solution that displays your pages by accessing the pages and rendering them to the user. There are various ways to accomplish this, including straight servlets as well as many frameworks (struts, spring, JSF, etc). Having your pages under /WEB-INF prevents them from being directly accessible to the end user per the J2EE spec.
6. Don’t rely on the security by obscurity argument that no-one will know your urls – automated tools can find these, and even intelligent testers often can make educated guesses about urls based on other urls … it’s a good bet that /account/delete exists if /account/view exists.
7. Use an application intrusion detection system (like AppSensor) in order to detect and possibly respond to attacks in production where people are doing things like forceful browsing to pages that don’t exist in your system.
8. If possible, use a tool or framework that already provides a solid authorization design to use for your environment so you don’t reinvent the wheel. There are many tools out there that do this for you, but your mileage definitely varies here. I’ll mention 2 that I’ve used: ESAPI and Spring Security. Spring Security works well for many cases since it’s quite simple and has good integration to Spring itself if you’re already using that framework. ESAPI is certainly more flexible and extensive, but you’ll likely have to do a bit more legwork to get the system hooked up to your application. Once done though, it does offer more features.
Here are the methods in the AccessController interface that is part of ESAPI. These are the methods you would use to perform authorization in your system:
public boolean isAuthorized(Object key, Object runtimeParameter);
public void assertAuthorized(Object key, Object runtimeParameter) throws AccessControlException;
boolean isAuthorizedForURL(String url);
boolean isAuthorizedForFunction(String functionName);
boolean isAuthorizedForData(String action, Object data);
boolean isAuthorizedForFile(String filepath);
boolean isAuthorizedForService(String serviceName);
void assertAuthorizedForURL(String url) throws AccessControlException;
void assertAuthorizedForFunction(String functionName) throws AccessControlException;
void assertAuthorizedForData(String action, Object data) throws AccessControlException;
void assertAuthorizedForFile(String filepath) throws AccessControlException;
void assertAuthorizedForService(String serviceName) throws AccessControlException;
So, in order to accomplish our task of verifying that a user has access to a certain url, you could use the is/assertAuthorizedForURL() methods, or the generic is/assertAuthorized() methods and pass in parameters specifying you want to authorize a URL and the actual URL data. Please note that this may require you write your own AccessController implementation to integrate with your application and configure ESAPI to use it as the AccessController. Alternatively, you could use one of the reference implementations and build your application so that it uses the ESAPI mechanisms to deal with authorization. Either way, ESAPI’s AccessController interface does allow flexibility in performing authorization of methods and data in your application.
So there you have it. URL authz is a subclass of generic authorization in your application. Authorization is an important concept to focus on during the entire development lifecycle, and URL authz is an important implementation detail that you need to get right when building J2EE apps.
Well, that’s it. Hope you’ve found this article helpful. Let me know if you have any questions or suggestions. Feel free to comment.
Other articles in this series:
Part 0: The OWASP Top Ten and ESAPI
Part 1: The OWASP Top Ten and ESAPI – Part 1 – Cross Site Scripting (XSS)
Part 2: The OWASP Top Ten and ESAPI – Part 2 – Injection Flaws
Part 3: The OWASP Top Ten and ESAPI – Part 3 – Malicious File Execution
Part 4: The OWASP Top Ten and ESAPI – Part 4 – Insecure Direct Object Reference
Part 5: The OWASP Top Ten and ESAPI – Part 5 – Cross Site Request Forgery (CSRF)
Part 6: The OWASP Top Ten and ESAPI – Part 6 – Information Leakage and Improper Error Handling
Part 7: The OWASP Top Ten and ESAPI – Part 7 – Broken Authentication and Session Management
Part 8: The OWASP Top Ten and ESAPI – Part 8 – Insecure Cryptographic Storage
Part 9: The OWASP Top Ten and ESAPI – Part 9 – Insecure Communications
Part 10: The OWASP Top Ten and ESAPI – Part 10 – Failure to Restrict URL Access
This article will describe how to protect your J2EE application from Insecure Communications attacks using ESAPI and other techniques. As with all of the detail articles in this series, if you need a refresher on OWASP or ESAPI, please see the intro article The OWASP Top Ten and ESAPI.
What does Insecure Communications mean? As usual, let’s check in with what OWASP says it is:
“Applications frequently fail to encrypt network traffic when it is necessary to protect sensitive communications. Encryption (usually SSL) must be used for all authenticated connections, especially Internet-accessible web pages, but backend connections as well. Otherwise, the application will expose an authentication or session token. In addition, encryption should be used whenever sensitive data, such as credit card or health information is transmitted. Applications that fall back or can be forced out of an encrypting mode can be abused by attackers.” [from here]
Insecure communications is an issue any time data traverses a communications path. For many standard J2EE apps, you’ve got a setup like the following you have to worry about:
- client browser -> web server
- web server -> app server
- app server -> DB server
-> LDAP server
-> JMS server
This is a simple but very common setup for J2EE apps. There are many more layers that could be added, and even a few could be taken away. Here’s the point: you need to think about insecure communications at every tier. You could make the argument that the browser -> web server connection is the most important, and I might even partially agree with that since that’s where the most nefarious things tend to live: on the wide open web. Still, the app server -> DB server connection is pretty important due to the data being transmitted. The point is, all the layers are important since important data is moving from point A to point B.
We know we’ve got to protect the data “in transit”, ie. as it moves across the wire, so …
Protecting against insecure communications could take many forms, but in the web app/J2EE world, it primarily means SSL/TLS, so that’s what we’ll discuss here. That’s right, our good old friend SSL/TLS. For the uninformed or if you just need a good refresher, have a look at this great doc produced by the good people at OWASP.
The use of SSL/TLS is not as easy as flipping a switch, as you might hope or think. There are various issues that have to be taken into consideration. I don’t want to simply re-hash all of the recommendations provided by OWASP, so I’ll try to focus on those most commonly seen by the J2EE crowd. (All the issues called out are important, but not necessarily developer-oriented – some are more frequently handled by network/sys admins.)
Most of us know what SSL/TLS does, but in case you don’t, the intent is to encrypt the data as it is in transit between points A and B. Note: There is no protection provided at the endpoints, but the issue at hand is protecting data while in transit, so SSL/TLS fits the bill.
Now that we know we need SSL/TLS, how do we implement it correctly? There are millions of pages dedicated to setting up SSL/TLS, so let’s assume you’ve gone through that and now need to require it for your particular application. There are various ways to do this. Let’s talk about a few.
1. Setup your web/app server to only have an SSL/TLS (https) enabled service listening, ie. no standard http service running, or at least block that port on the firewall. This option is fine if you can do it, but there’s usually a reason you can’t, and in addition, it doesn’t help if anyone ever comes along and adds http back in – at that point – you’re back at square one.
2. The standard Java way is to add a transport guarantee to the web.xml file. The following snippet shows an example.
<security-constraint>
<web-resource-collection>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
This snippet requires all requests that match the pattern “/admin/*” to go over SSL/TLS. If they are requested over standard http, the request will be redirected over https. This is a fine solution if your application is structured in a manner that you can protect the appropriate urls by using simple url pattern matching. If that’s not true, this method can lead to a rather verbose configuration.
3. The ESAPI way of performing this task is also very simple. This can be done by using the assertSecureChannel method as in the following snippet.
//this method can throw an AccessControlException
//uses the current http request - there is an overloaded method that accepts
//a specified http request object as a parameter
ESAPI.httpUtilities().assertSecureChannel();
If this method finds that SSL/TLS is not being used, it does not attempt to redirect you there. Rather it throws an AccessControlException, which can then be caught and dealt with appropriately. If you’d like all of your pages to require SSL, this code could simply be added to a J2EE filter configured to execute on all requests (“/*”).
4. Other frameworks … there are tons of frameworks, or even custom code that could be used to perform this task.
Ok, now we’ve seen a bit about how to require SSL/TLS in the J2EE environment, let’s talk about a few of the relevant gotchas that J2EE folks have to deal with.
1. Make sure you use SSL/TLS between all tiers. Don’t cover just the browser -> web server. Ensure every path is protected.
2. Require SSL/TLS for all login (including page you login from) pages as well as any authenticated pages after login.
3. Use http POST as opposed to http GET for any sensitive information. This is always true, but makes even more sense with SSL/TLS as the POST data is protected by SSL/TLS, but the url is not as that is required to make the request. This means others viewing your request can still see your sensitive data since it’s part of the url.
4. Mark all your user cookies secure: this prevents your browser providing the session cookie to an attacker in the event of an attack that causes you to request a non-SSL/TLS url from the application. If the cookie is not secure, your browser will still happily provide the cookie even if the site doesn’t support http … protect your users.
5. Don’t put any insecure content on your secure pages. This could allow an attacker to “inject” content into the page and have that information presented to a user as if it came over the SSL/TLS connection.
6. Often times it is just easier to protect the entire site with SSL/TLS. This is fine, but be aware of any performance concerns. SSL/TLS does require overhead. It’s gotten pretty optimized over the years, but it will always be slower than http. If you are on a high volume site, think about what data you are presenting, and test both with and without SSL/TLS to verify any performance differences. However, no matter the performance difference, always follow the other rules listed here. Protection of data is better than a slightly faster site (since we are talking about security here :>).
7. Stay educated and patch when necessary. SSL/TLS has been a standard technology for many years now. However, just within the past few months, there have been reasonably large bugs found and resolved. Largely, these bugs have to do with implementation and not design, however you need to stay educated nonetheless.
8. Comply with policy / legal regulations. For some types of data (credit cards and SSN’s for instance), there are legal requirements imposing the use of SSL/TLS to protect the data in transit. These may or may not apply to you, but be sure you know, because failing to meet them could be a very bad thing indeed.
So there you have it. SSL/TLS is fairly well known, but there are some things to look out for when building a site that uses it.
Note: In very recent days, news came out that Robert “RSnake” Hansen and Josh Sokol were able to poke some pretty major holes in SSL. I have not had the time to adequately research their findings, but you should. I do assume, based on the credence of the researchers, that the research is sound, so pay attention. This does however point to the fact that a defense-in-depth approach to security as well as building security in at every layer are best practices.
For some additional background and information on SSL/TLS, see the Transport Layer Protection Cheat Sheet referenced above.
Well, that’s it. Hope you’ve found this article helpful. Let me know if you have any questions or suggestions. Feel free to comment.
Other articles in this series:
Part 0: The OWASP Top Ten and ESAPI
Part 1: The OWASP Top Ten and ESAPI – Part 1 – Cross Site Scripting (XSS)
Part 2: The OWASP Top Ten and ESAPI – Part 2 – Injection Flaws
Part 3: The OWASP Top Ten and ESAPI – Part 3 – Malicious File Execution
Part 4: The OWASP Top Ten and ESAPI – Part 4 – Insecure Direct Object Reference
Part 5: The OWASP Top Ten and ESAPI – Part 5 – Cross Site Request Forgery (CSRF)
Part 6: The OWASP Top Ten and ESAPI – Part 6 – Information Leakage and Improper Error Handling
Part 7: The OWASP Top Ten and ESAPI – Part 7 – Broken Authentication and Session Management
Part 8: The OWASP Top Ten and ESAPI – Part 8 – Insecure Cryptographic Storage
Part 9: The OWASP Top Ten and ESAPI – Part 9 – Insecure Communications
Part 10: The OWASP Top Ten and ESAPI – Part 10 – Failure to Restrict URL Access