Technical Insight

Beware the HTTP Path Parameter in Java

Please forgive the title, but today’s topic is something to be wary of if you write (or use) any access control / authorization type code in Web-based J2EE apps: HTTP URL path parameters. Many people are unfamiliar with HTTP URL path parameters (and they are uncommon), but they are something you should be aware of. A simple description of url path parameters can be found here. Essentially, path parameters are the bit of a url path that immediately follows a semi-colon (a semi-colon is the most popular path parameter delimiter). So, here’s an example of 2 urls, each with an http path parameter:

http://www.mysite.com/admin/UpdateUserServlet;jsessionid=OI24B9ASD7BSSD

http://www.mysite.com/admin/UpdateUserServlet;/user/HomeServlet

We’ve all probably seen the first example, where a jsessionid gets attached to our url, many times. However, take a look at the second example. Pay very close attention to what is being presented here: The request is going to the administrative UpdateUserServlet, but with a path parameter of /user/HomeServlet. Now, what problems could this create? Well, in most cases there are actually two issues that must be dealt with.

Issue 1 – The Server Product and Version

The first issue is how your servlet container/app server product and version handle certain request APIs. That’s because different products – and even versions – apparently deal with http path parameters in different ways. (I have yet to do the work that determines which servers and versions are affected, but you should do that in your own environment, as even configuration changes can apparently cause slightly differing behavior. These variations are caused by – read “blamed on” – a lack of clarity in the servlet spec regarding path parameters.)

This first problem can be observed when using certain API calls from the HttpServletRequest object, and then seeing how those APIs handle path parameters. Two of the affected methods are getContextPath() and getServletPath(), where there are variations between whether or not these calls actually strip out any path parameters depending on server product and version. Again, this is testing that you will need to do on your own. The alternative to testing is to make assumptions, and you’ll see below what can happen when those assumptions are wrong.

Issue 2 – Your Code

Here is where the actual security problem really shows up…when we use these APIs. One of the most common uses of the Request URL related APIs is for writing access control / authorization code. Many access control frameworks or internal codebases use a url mapping concept of some kind. These concepts vary widely in how they are implemented, but a simple example might be: Anything with “/admin/” in the path requires the admin role, or anything that ends in “UpdateServlet” requires the manager role. Let’s use the “ends with” example and walk through some code.

String uri = request.getRequestURI();   //note getRequestURI will always return the full path with path parameters but not request parameters

if (uri.endsWith(“UpdateServlet”)) {

//require the manager role here

} else {

//just require standard user role

}

Although this is a very trivial piece of code, it will be similar in spirit to what is in lots of access control code in j2ee apps. In this example the developer was expecting the user to send a request that looked like:

http://www.mysite.com/app/UserUpdateServlet

when they were trying to get to the update servlet. But what happens if the user sends a request like:

http://www.mysite.com/app/UserUpdateServlet;/app/UserReadServlet

THIS IS THE PROBLEM! Now that the app code has checked the URI, and sees that it ends with ReadServlet, and not UpdateServlet, the app code requires only the standard user role, and the access control check passes. However, the app server/container sees that the ACTUAL request is going to UserUpdateServlet, and allows the user to go there. Now we have an access control bypass issue! The user has been able to circumvent your “protection.”

DOH! Ok, now what…?

Fixing the Problem

There are several ways you can address this issue, and each way varies in difficulty and correctness.

1. You can whitelist all of your allowed requests and compare them to pre-determined acceptable urls, but that could become cumbersome with a very large app.

2. You can perform some cleansing (stripping) of the url path parameters, but that can be an issue if your app server allows various path parameter delimiters.

3. You can compare from the start of the URI or path, instead of checking the end. This would likely have the same limitations as the whitelist option.

4. You should definitely check your app server/container (on every upgrade, as well) to see what its actual behavior is regarding path parameters.

5. You may be able to perform your access control check at the beginning of a request handling piece of code, like a servlet, or action. That way, you know the code that is actually being executed, so it’s the url you should be verifying. However, this method lacks centralized control over your checking process.

There are certainly more options than those methods listed here, and you know best what will work in your code, but hopefully these five options will help as a starting point.

References

As an example of applicability, there was a relatively recent important bug in the Spring Security (formerly Acegi) project that was caused by the path parameter issue discussed here. More information can be found at the following 2 urls:

http://www.springsource.com/security/cve-2010-3700

http://seclists.org/fulldisclosure/2010/Oct/437