John Melton's Weblog
Java, Security and Technology

Year Of Security for Java – Introduction

No Gravatar

Year Of Security for Java

This will serve as the introduction for a new series that will have roughly 1 article per week for a year. This series will be different from my last series (OWASP Top Ten – Java) in that each article will be pretty short and focused. There are several motivations for this series:

1. Get some old topics written down
2. Research some new technologies
3. Write
4. Learn
5. Answer questions from Java friends

It’s the last one that serves as the primary motivation. In my work with Java developers, I understandably get asked a lot of questions about security. These are pretty far-ranging from the “what is this thing I heard about” to “how do I do this very specific thing correctly”. Developers are sharp, but have a lot they are held accountable for, of which security is only one. In this series, I hope to highlight some of the common issues the developers I work with ask me about frequently, as well as point out a few things they probably should be asking about, but don’t know to just yet.

If you have specific suggestions for articles you’d like to see, feel free to email me at domain_name at gmail dot com or on twitter (_jtmelton).

Hope you enjoy.

Technorati Tags: ,

Beware the HTTP path parameter

No Gravatar

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 them (as they are uncommon), but they are something you should be aware of. A nice simple description of url path parameters can be found here. Essentially path parameters are the bit of a url path that comes after a semi-colon (semi-colon is the most popular path parameter delimeter). 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 seen the first example probably many times where a jsessionid gets attached to our url. However, take a look at the second example. Pay very close attention to what is being presented here. This represents a request that is going to go to the administrative UpdateUserServlet, but with a path parameter of /user/HomeServlet. Now, what could be the problem here? Well, there actually turns out to be 2 different issues to deal with in most cases.

Issue 1 – The server product and version

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

This problem can be seen when using certain API calls from the HttpServletRequest object and 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 and version. Again, this testing is left as an exercise to the reader. We’ll see below what can happen when we make poor assumptions here.

Issue 2 – Your code

Here is where the actual problem really shows up … when we actually use these APIs. One of the most common uses is for writing access control / authorization code. Many access control frameworks or internal codebases use a url mapping concept of some kind. They 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
}

This is a very trivial piece of code, but will be similar in spirit to what is in lots of access control code in j2ee apps. Here 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

HERE’S THE PROBLEM! Now the app code has checked the URI, and sees that it ends with ReadServlet and not UpdateServlet, so it only requires the standard user role, and the access control check passes. But the app server/container sees that the ACTUAL request is going to UserUpdateServlet, and allows the user to go there. Now we have a 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 could address this issue, and each option varies in difficulty and correctness.
1. You could whitelist all of your allowed requests and compare them to pre-determined acceptable urls, but that might get 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 delimeters.
3. You can also compare from the start of the URI or path instead of checking the end. This might be similar to the whitelist option
4. Another option that should definitely be used is to check your app server/container (on every upgrade as well) to see what it’s actual behavior is regarding path parameters).
5. Another option might be 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 that’s the code actually being executed, so it’s the url you should be verifying. This has the problem of a lack of centralized control however.

There are certainly more options here, and you know what will work in your code, but hopefully the options above help as a starting point. Hopefully you found this information helpful and are able to update your projects to fix the issue if it exists.

References

Much of my research for this article came from an important bug in the Spring Security (formerly Acegi) project that was caused by this path parameter issue (bug found by Ed Schaller). 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

Special Author Note

This topic was first shared with me by Abraham Kang. He both introduced me to this issue and reviewed this article for me. Thanks Abraham!

Technorati Tags: , , ,

Application Intrusion Detection with OWASP AppSensor

No Gravatar

Introduction

This article is a basic introduction to AppSensor, an OWASP project that’s been gaining a lot of traction recently. It’s a fairly simple concept, and one that I think (and hope) will be implemented in lots of applications in the near future. If you’d rather watch a video about AppSensor, here is a good one from Michael Coates, the project lead. Alternatively, here is a very quick video of a demo of AppSensor. So, let’s get started …

What is AppSensor and why should I care?

AppSensor is an implementation of an idea called application layer intrusion detection. The concept is very simple. While we have controls like intrusion detection at the network layer and web application firewalls at the web layer to detect attacks, these tools work outside the application where they are missing some context. We don’t currently have a good paradigm to represent attack detection and possible response inside an application, unless you completely roll your own. There is actually an implementation of this concept in ESAPI, (see the IntrusionDetector interface) and AppSensor’s implementation can be used as a drop-in replacement for the default handler provided by ESAPI, but more on that later. For now, let’s talk about why you need AppSensor.

So, you do good threat modeling, good security architecture, design, coding, code reviews, white/black box security scans, etc. … great, but you still have security holes. It’s a fact of life that today’s complex applications, and the heavily constrained timelines under which they are built, lead to security holes. If you have an application of any decent size, you are almost assuredly vulnerable to something. You should absolutely continue good secure development practices – these are crucial – but we need more.

Let’s consider those folks that actually end up breaking into our apps. It turns out that attackers vary in how good they are. Some are better than others; some are phenomenal, though the bar has continually been lowered due to automated tools. However, any attacker, bad, good or great, almost always has to try several things in order to successfully break into your app (for many classes of vulnerabilities). If they get in on the first try, they’re either lucky, or your app is so insecure, there’s not much that can help it. So, what if we could differentiate the bad guys before they actually get in? That’s the idea of AppSensor. Let’s assume that it takes an attacker 20 tries to find a field he can manipulate to get an XSS bug, but you can detect that he’s trying to find an XSS bug in 5 tries. Now, we have the advantage – we’ve determined he’s a bad guy, and can respond before a successful attack occurs.

The AppSensor project represents both the concept and implementation of an application layer intrusion detection system. First, a little info (and a few references) about the conceptual pieces. There are 3 basic concepts in AppSensor:
1. Detection
2. Evaluation
3. Response

Detection is the process of actually recognizing that an attacker is performing an attack. This involves adding code (which we’ll show a sample of below) to points that are deemed valid “detection points”. These are points in the code where we know the expected reasonable path(s) a user should be performing, and have a way to detect the user has varied from the path. Consider the case where a user submits a GET request when the form is setup for a POST. That should NEVER happen in a normal circumstance unless the user is doing some modification. A collection of these detection points has been created by the team in order to help you get started in determining reasonable locations to check for attacks.

Evaluation is the process of evaluating all the actual attack detections across the system for all users and determining when it is appropriate to trigger certain response actions. This is, for lack of a better term, the “engine” of the system, and is really behind-the-scenes code for anyone who wants to implement AppSensor. The interface to this would be the threshold setup (shown below)

Response is the activity of actually responding when it is determined an attack has actually occurred. A collection of these response actions has been created by the team in order to help you get started in determining reasonable responses for attacks.

These are the basic components of the system, but in order to really understand the system, feel free to read the book. This was a mammoth effort to document this concept, and as open source projects go, is some of the best documentation available.

How do I use it?

My key part in the project has been from the development side. For a quick “getting started” version of using AppSensor that has some good information (I wrote it :) ), see the developer guide. Here I’ll show the few basic steps to getting going. I’m going to show the setup here as if you’re using OWASP ESAPI in your project. This is by no means required, but since there is already the concept of intrusion detection, it makes life a bit simpler. Also, since ESAPI is a set of distinct controls, you can use some and not others. So, here are the steps:

1. Replace default ESAPI intrusion detector with AppSensor intrusion detector.

ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
becomes
ESAPI.IntrusionDetector=org.owasp.appsensor.intrusiondetection.AppSensorIntrusionDetector

2. Add threshold configuration. There is an appsensor.properties file (see dev guide for details) that you can use to configure thresholds for when an attack is considered to “trigger” a response. Here’s an example configuration for a threshold.

# http://www.owasp.org/index.php/AppSensor_DetectionPoints#ACE2:_Modifying_Parameters_Within_A_POST_For_Direct_Object_Access_Attempts
# number of intrusions in a specified segment of time that constitutes the upper threshold - once crossed, it's considered an "attack"
IntrusionDetector.ACE2.count=3
# segment of time (in seconds)
IntrusionDetector.ACE2.interval=3
# list of actions you want executed in the specified order as the threshold for this intrusion is met - ie. log the first time, logout the user the second time, etc.
IntrusionDetector.ACE2.actions=log,logout,disable,disableComponent
# some integer - duration of time to disable
IntrusionDetector.ACE2.disableComponent.duration=30
# some measure of time, currently supported are s,m,h,d (second, minute, hour, day)
IntrusionDetector.ACE2.disableComponent.timeScale=m
# some integer - duration of time to disable
IntrusionDetector.ACE2.disableComponentForUser.duration=30
# some measure of time, currently supported are s,m,h,d (second, minute, hour, day)
IntrusionDetector.ACE2.disableComponentForUser.timeScale=m

3. Add detection points into your code. This is the hardest actual work – it requires finding those places in your codebase where you can check for an attack. This example shows an instance where we’ve decided that 404 requests could be considered an attack. In this case, a single request or even a handful might be legitimate, but dozens or more probably point to a scanner of some type looking for vulnerable code.

//This example snippet might be placed on a jsp that handles HTTP 404 errors.
//When the page is accessed, this code notifies AppSensor that an invalid page request was made.
//Notice that the exception is created, not thrown

new AppSensorException("ACE3", "Invalid request", "Attacker is requesting a non-existent (404) page (" + requestedURI + ")");

Conclusion

So, that’s it – pretty simple. AppSensor is another tool in the toolbelt for the security developer/practitioner. It is an idea that can be implemented in an application fairly easily and with great effect. It has the power to detect and prevent an attack before it is successful, and has the key advantage of context within an application, allowing us to respond to the user that performed the attack.

That’s it for now. I may post more detailed information about AppSensor as the project progresses. For now, feel free to comment here and let me know what you think.

Credits

I should briefly mention the other members of the core team: Michael Coates is the project lead, and Colin Watson is another key member of the team.

Resources

AppSensor Project Page
AppSensor Book
AppSensor Developer Guide

Technorati Tags: , , , , , , ,

Preventing Log Forging in Java

No Gravatar

This article will provide a quick overview of log forging and discuss a couple simple solutions to prevent it.

First, what is log forging?

Logging is one of the most common things that an application does. Logging is a very generic term that can mean lots of different things, from debug style logging for the developer, up to and including functioning as the system audit log. The 3 most common logging mechanisms I see in real world use are:
1. System output (System.out.println)
2. 3rd party logging library (log4j, commons logging, slf4j, etc.)
3. DB Logging

System output
System output is a functional mechanism, but tends to provide spotty information at times, since developers often don’t log everything they should in order for the log to be functional. A simple example of this is that essentially all logging should include a timestamp and at least the logged in user if applicable, but System.out logging often doesn’t include these 2 basic pieces of information.

3rd party logging library
The 3rd party logging libraries are the workhorses of the java logging world. They are probably the most used option and for good reason. The popular frameworks provide very simple configuration, offer all the basic features (and even some advanced features), and can be setup to log the same “meta-information” for each log entry (such as timestamp, username, etc.).

DB Logging
Most often DB logging is used for log/audit data that needs to be maintained for a reasonable amount of time. If there is auditing going on for the application, a DB is a popular choice since the audit records can actually reference the data it is about using the relational DB mechanisms already built into the DB product. Also when logging to a DB, there is usually a reasonable amount of data that is stored. This is likely due to the fact that someone sat down and thought out what data should be stored, and created the DB schema to store that info – that way the standard for what data needs to be logged is perfectly clear to the developer.

Now that we’ve talked about a few basic types of logging, let’s see what log forging is. Let’s consider this bit of code.


String previousPage = request.getParameter("prev");
logger.info("Previous page from request was: " + previousPage);

This simple bit of code just writes a request parameter to the log. Pretty simple. Let’s consider two scenarios here. If the user is using the application as intended, something like the following might be sent in – “prev=viewCart”, telling the app the page the user was coming from was a view shopping cart page. This would result in the following being written in the log.


[2010-10-21 18:45:15] [bill] Previous page from request was: viewCart

Now what would happen if an attacker instead decided to modify the request parameter and instead entered “prev=viewCart\r\n[2010-10-21 18:45:15] [steve] Account successfully created” as the request parameter? (Note the data I entered above is not actually URL encoded for clarity, but would be in a real example) Now the log will look like the following:


[2010-10-21 18:45:15] [bill] Previous page from request was: viewCart
[2010-10-21 18:45:15] [steve] Account successfully created

Now the attacker has been able to create a forged entry in the application log which reduces the value of the logs, and frustrates any forensic type activities. This is the essence of log forging.

So how do I prevent it?

There are various options to prevent log forging. I’ll discuss just a few and my opinions of them.

1. Validate all input that could be put in the log file. This would involve doing strict whitelist validation to make sure that characters that pose issues in logs are not available to the attacker. This option, in my opinion, would be the least likely to work. The truth is that you’d have to validate lots of data, and if it failed validation, it wouldn’t get logged. That data could be valuable debugging information or even audit data. This is my least favorite option, and I’ve only actually seen it once in practice.

2. Log to a database. Essentially logging to a database does prevent log forging since carriage return / newline mean nothing in that context, but it introduces another possible exploit: SQL Injection. For information about how to prevent SQL Injection properly, please see: The OWASP Top Ten and ESAPI – Part 2 – Injection Flaws. This is an ok option if you need to use a database for auditing, but I wouldn’t use it for standard logging. If you do use it, be sure to use a proper SQL Injection prevention mechanism.

3. Encode all output. This is a simple and elegant solution, and my personal favorite. There’s not that much to it – just encode those characters you need to in order to prevent log forging, and everything else get’s logged the same. You can develop a simple wrapper around your favorite logging utility in order to do the log forging prevention work, and use the logging utility for all it’s other features. Luckily the good people who built ESAPI already did this for you. They have a logging component built into ESAPI that contains this log forging protection. An example for wrapping the popular Log4j library is here. Here is a snippet of code that shows their encoding in action.


// ensure no CRLF injection into logs for forging records
String clean = message.replace( '\n', '_' ).replace( '\r', '_' );
if ( ESAPI.securityConfiguration().getLogEncodingRequired() ) {
    clean = ESAPI.encoder().encodeForHTML(message);
    if (!message.equals(clean)) {
        clean += " (Encoded)";
    }
}

As you can see, the class simply replaces all carriage returns and line feeds with underscores, then, if configuration dictates, HTML encodes the message. If the original message to be logged is different from the encoded version, a simple ” (Encoded)” string is tacked onto the end of the log entry to denote that it required encoding of some type.

Other notes

Another possibility when writing data to a log that may or may not be true in your environment is XSS. Though it doesn’t sound clear at first, consider this possibility. You log all of your data to a flat file, then your team, an auditor, system admin, or anyone comes along and opens your log file in a fancy web based log viewer. If XSS attacks are stored in the log, then the log viewer would then be susceptible to XSS. The best solution, in my opinion, would be to ensure your log viewer is protected from XSS. I feel that when you output data to a particular location, you should protect against the attacks specific to that location, ie log output should protect against log forging. However, it is helpful to be aware of issues like this to understand the full situation. Also note in the ESAPI code above, HTML output encoding is performed, and could help prevent this situation as well.

Wrap-up

So, as you can see, log forging is an issue that affects pretty much every J2EE application out there. It’s fairly simple to understand and fairly simple to solve. Hope this helps. Let me know if you found it useful, or if you have dealt with log forging differently.

Technorati Tags: , , , , , ,

The OWASP Top Ten and ESAPI – Final Summary

No Gravatar

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.

Technorati Tags: , , , ,

The OWASP Top Ten and ESAPI – Part 10 – Failure to Restrict URL Access

No Gravatar

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’s the problem?

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.

Where do we go from here? ….

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

Technorati Tags: , , , , ,

The OWASP Top Ten and ESAPI – Part 9 – Insecure Communications

No Gravatar

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’s the problem?

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 …

Where do we go from here? ….

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

Technorati Tags: , , , , , , ,

The OWASP Top Ten and ESAPI – Part 8 – Insecure Cryptographic Storage

No Gravatar

This article will describe how to protect your J2EE application from Insecure Cryptographic Storage issues 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’s the problem?

First, let me start off by saying Crypto is hard, really hard. There are various aspects to cryptographic security, and all of them are difficult to get right. Some examples include creating an algorithm, using the algorithm and key management. Typically, developers aren’t creating algorithms. That is often done by (really smart PhD) mathematicians, and a small set of developers who implement those algorithms. However, many developers do “use” those algorithms to do some type of encryption in their applications. Developers also have to deal with key management.

Let me additionally state here that I am by no means an expert on this topic. I have some background with crypto, but I certainly don’t have a lot, so much of what’s presented here are generally accepted best practices, and don’t necessarily come from my own experience. OK, on to the detail…

What does Insecure Cryptographic Storage mean? As usual, let’s check in with what OWASP says:

“Protecting sensitive data with cryptography has become a key part of most web applications. Simply failing to encrypt sensitive data is very widespread. Applications that do encrypt frequently contain poorly designed cryptography, either using inappropriate ciphers or making serious mistakes using strong ciphers. These flaws can lead to disclosure of sensitive data and compliance violations. ” [from here]

So, this is pretty self-explanatory. If something can go wrong, it will with crypto. There are lots of reasons why this is probably true. First, it’s hard to get right in the first place – there are a lot of moving parts. Second, developers typically don’t understand it as well as other aspects of software. Third, it’s rare. A small number of people have been dealing with crypto for a long time, but it’s only a relatively recent development that LOTS of devs have been impacted by it. Part of this is due to new regulatory constraints that require encryption of some kind for data at rest.

Where do we go from here? ….

Now that we’ve established that crypto storage is hard, let’s talk about a few common approaches that can help remedy the issues.

1. Stay Educated. This is an important step. Due to the increase in computing power that we gain every year, as well as new cryptanalytic (breaking a crypto algorithm) attacks, the list of “good” algorithms is somewhat of a moving target. Typically, if you’re in the US, NIST (nist.gov) is a good place to check as they set crypto standards. Additionally your workplace may have a set of approved standards that you would need to follow. Also, read books to learn about crypto. You may not be the mathematician coming up with the algorithms, but there is much to learn here that will benefit you.

2. Use good algorithms. This is a follow on to the first point, but it’s important enough to call out separately. Do NOT create your own crypto algorithm unless you’re an expert – it is very difficult to get right. Even the guys at the top of the field tend to create algorithms as part of a team, and those algorithms are generally only accepted as secure after years of analysis by peers. Additionally, do NOT use old, weak algorithms. These could help to a point, but many of them are able to be broken in minutes or even seconds these days. It’s easy enough to use solid algorithms, so educate yourself and make the right choices.

3. Do good key management. This is a broad topic which I don’t even pretend to comprehend fully. There are many possible ways this could work. At the current time, it’s even an active discussion among the ESAPI developers over how they plan to do it. There are various options from just hard-coding a key (DON’T DO IT) all the way up through large commercial systems to do key management for you. Spend some time thinking over your requirements, and make an informed decision.

4. Encrypt credentials. Pretty much every J2EE system connects to a DB, LDAP, web service or some other repository. The credentials to make these connections should be encrypted to prevent easy access to these data storage systems.

5. Don’t store sensitive data if it’s not a requirement. Storing sensitive data is what introduces these complexities. It’s better if you don’t have to worry about them in the first place. Only store sensitive data when there is a firm legal or business requirement.

6. Know your regs. Know your legal and regulatory requirements. There are certain provisions in these requirements that prevent the storage of certain pieces of data EVER. Storing this data not only places additional requirements on your application, it can carry some hefty fines for breaking these laws.

7. Simplify. It’s the old KISS principle. However, when it comes to crypto, it’s certainly true. Do the least you’re required to do in order to store sensitive data securely. The more complex a system, the more difficult it is to secure generally.

8. Store the key/password/data separately. These pieces of information make up your data protection mechanism. Storing them in the same place makes it simpler for an attacker to gain access to all of them. If they are stored separately, an attacker may still gain access to all of them, but it’s more difficult.

9. Use filesystem controls. Operating systems have filesystem access controls for a good reason – so you will use them. Protecting data is a defense in depth task, but protecting the keys, passwords, etc. with filesystem controls locked down so only the appropriate user(s) has access is a best practice measure to help secure your data.

One thing to note here is that I did not add any sample code snippets for this topic. This was intentional. At the moment, the ESAPI encryptor implementation is going through a fairly significant update and code review. There is still some discussion of major changes coming. Either way, ESAPI will provide support to encrypt/decrypt and hash data. The interface to that functionality may change, but the library will provide those features – you can be sure of it.

Well, that’s it. Hope you’ve found this article helpful. Let me know if you have any questions or suggestions.

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

Technorati Tags: , , , , ,

The OWASP Top Ten and ESAPI – Part 7 – Broken Authentication and Session Management

No Gravatar

This article will describe how to protect your J2EE application from Broken Authentication and Session Management issues 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’s the problem?

What does Broken Authentication and Session Management mean? As usual, let’s check in with what OWASP says:

“Flaws in the main authentication mechanism are not uncommon, but weaknesses are more often introduced through ancillary authentication functions such as logout, password management, timeout, remember me, secret question, and account update.” [from here] They go further to say the goal in resolving these types of issues is “to verify that the application properly authenticates users and properly protects identities and their associated credentials.”

The idea here is that of providing assurance that a given user can gain access to their account if one exists, and only that account. This is a complex topic that covers many aspects, only some of which we’ll be addressing here.

If this issue is not properly addressed, various problems arise. These can include accounts being hijacked, credentials stolen, data being compromised, etc. Beyond the issue of losing data, there is obviously a huge reputational risk with these types of issues as well. Essentially you are dealing with the keys to the kingdom – if they’re lost – noone trusts your application!

Where do we go from here? ….

Now that we’ve briefly discussed what can occur if this issue is not addressed properly, let’s talk a bit about some steps we can take that can remediate the issue when properly applied. For this section, I’ve heavily used this article.

1. Use the built-in session management features. Session management is difficult to get correct. Even though app servers have been doing it for years, there are still bugs being reported with reasonable frequency. It is foolish to think that you’ll do better on your first try.

2. With regards to authentication:
- Use a single entry point. Don’t write and rewrite auth code – write it once, and try to get it right
- Make sure login starts on an SSL-protected page.
- Invalidate the HttpSession before login and after login. This helps prevent session fixation attacks where an attacker can specify a session id for a user to use. Invalidating the session id guarantees the attacker doesn’t have access to the new session id.

3. Get logout right. Make sure it’s accessible throughout the application with a single click, and make sure it invalidates the session and anything else that may be being used in the auth process, such as a cookie.

4. Add a timeout. A session timeout (and associated handler) should be configured to grab sessions that have timed out and clean them up so they are not available for reuse. Obviously, the shorter the time for the timeout, the less risk – the longer the time, the more user friendly. Find the balance you need for your application – personal opinion – 30 minutes is often plenty of time for many sites with anything valuable on them.

5. Ensure you are using safe related functions. Functions like security questions and answers, forgot password, forgot username, change password are difficult to get right. When done improperly, they can leak information about the account, and outright cause loss of credentials. Be sure to find as much information as you can about how to get these functions right before implementing them. Then test them to death – both unit tests and functional tests.

6. If you’re in a situation where it’s possibly, use strong authentication. This would mean using 2 or more of the 3 possible factors: something you know, something you have, and something you are. Typical username/password (something you know) systems are prevalent, but if you could add a token (something you have), then you levy an additional requirement on the user, but you also reduce the risk of someone gaining access that shouldn’t (assuming your authentication is sound).

7. Default to not authenticated. It sounds simple, but folks do (more often than you might think) code systems that default to authenticated on login. The code would look something like this:


//BAD - DON'T USE
public boolean login(String username, String password) {
    boolean isAuthenticated = true;

    try {
	//make calls to backend to actually perform login against datastore

  	if (! authenticationSuccess) {
	    isAuthenticated = false;
	}
    } catch (Exception e) {
	//handle exc
    }
    return isAuthenticated;
}

As you can see, the user is set to authenticated by default, and if an exception is thrown, the user is logged in. This would fall under the security mantra of secure defaults. Unfortunately code like this is surprisingly common in systems today (but hopefully not yours).

OK, well that’s all I’ll cover in this article. Let me add just one more simple word of caution: authentication and session management are difficult and complex topics. It is very naive to think that you will get it right on your first try. Please consult with folks like OWASP and other secure development resources to get a broader picture of the types of issues that need to be addressed in this space. Educate yourself as much as you can. Use other’s good code that’s been vetted if it’s available. If not, take your time – think through the types of attacks that are possible, do code reviews, get others to do code reviews, and test test test.

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 on techniques you are using to correct Broken Authentication and Session Management issues.

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

Technorati Tags: , , , , , ,

The OWASP Top Ten and ESAPI – Part 6 – Information Leakage and Improper Error Handling

No Gravatar

This article will describe how to protect your J2EE application from Information Leakage and Improper Error Handling 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’s the problem?

As usual, let’s check in with what OWASP says it is:

“Applications frequently generate error messages and display them to users. Many times these error messages are quite useful to attackers, as they reveal implementation details or information that is useful in exploiting a vulnerability.” [from here]

This can be broken down further into two basic categories from the web end user perspective.

  • An error message with too much detail (eg. stack trace, sql statement, etc) is splashed onto the screen.
  • An error message for a specific function varies depending on minor changes to the input enabling the user to determine exactly what error occurred (eg. a different error message for a bad username and a good username/bad password – this tells the attacker the username is valid.)

The two categories above really differ at the level of concern. The issue of too much detail often stems from sending information to the screen that is internal to the application – information that has more to do with the code and/or configuration of the application. Often times these messages are NEVER intended to be shown to the end user. This is a technical issue. The issue of specificity in error messages has to do with user messages that ARE intended to be seen by users. However, the wording for them is poorly chosen. This is a business issue of coming up with appropriate messages.

One sidebar note here is that of exception handling. Appropriate exception handling in Java is often a topic of debate. One of the main issues stems from that of the difference between 2 core classes: Exception and RuntimeException.

1. The former (Exception and any subclass) is referred to as a checked exception, meaning that any code that calls any other piece of code that may throw one of these exceptions HAS to handle it in some way, either by wrapping the code in a try/catch block, or by explicitly throwing the same exception (or a superclass) in the method signature. Proponents argue that this forces developers to be aware of the types of exceptions that code may throw, and deal with them appropriately. Opponents argue that this can complicate code and cause many developers to trap exceptions and not deal with them properly or at all, which is worse than bubbling them up in the first place.

2. The latter (RuntimeException and any subclass) is referred to as an unchecked exception, meaning code may or may not deal with these exceptions, it is their choice. Proponents argue that this allows flexibility in handling exceptions and provides for cleaner code. Opponents argue that exceptions of this variety essentially don’t “notify” their callers of the types of exceptions they may throw, and therefore the calling code is less reliable.

Honestly, no matter where you land in this debate, the issue of information leakage still exists for J2EE web applications today. At the very least, NullPointerExceptions exist in every J2EE app known to man, so it’s still possible to bubble up an exception even if your entire application exception heirarchy is checked, so the information presented here is still very relevant.

So far, we’ve noted the types of application error messages that can be leaked to the end user, as well as a brief discussion about the internal exception management of an application.

Where do we go from here? ….

There are various specific techniques for dealing with information leakage and improper error handling. Several of these techniques are valid. The point of this article is not to try and enumerate all of them, but to create a working safe solution that can be implemented. Your solution may vary in style, but the underlying principles should be the same: preventing (as much as is reasonable) the attacker from gaining information from your system that can be used in an attack.

Again as above, we’ll break the discussion into 2 parts: missing exceptions altogether, and handling error messages improperly (often by giving too detailed of an error message).

1. First we’ll discuss how to resolve presenting the user with unhandled exceptions. These fall into the category of “should NEVER be presented to the user”. First, these occur because all possible exceptions are not handled in every piece of code. The first thing to note here is that your application should have a standard for how it handles exceptions. Ignored exceptions are an epidemic in Java (and other languages), but that is too large a topic to tackle here. No matter your standard for handling exceptions, inevitably there are going to be some places where you might miss them. Even if you handle everything you think you ought, there may be a JSP issue that would present an exception to the user.

My suggestion for how to handle this is a J2EE standard technique and quite simple to implement: configure an exception handler in the web.xml configuration file. An example of how to do this is below.


<error-page>
  <exception-type>java.lang.Throwable</exception-type>
  <location>/error.jsp</location>
</error-page>

This is a very simple solution to handle any subclass of java.lang.Throwable (which covers all types of exceptions) that gets bubbled up through the application, whether by a servlet, jsp, or some framework specific code and preventing the user from seeing it. What it will do then is redirect the user for any previously unhandled exception it catches to /error.jsp. This page should have some generic text on it stating that an error occurred, and should not give specifics as to what that error is.

Note: MVC frameworks often offer an exception handling mechanism that is intended to do this same thing. However, be aware that many of these do not work if the exception occurs in the JSP page since that is outside the scope of what the framework controls. Another viable option in many cases is to use a J2EE filter to do appropriate exception handling since the filter is accessed both before and after the servlet/jsp request is performed, and can catch exceptions that occur in either of them.

2. The second type of issue is caused by giving the user too much information in an error message on the screen. Often times the error message that is sent to the screen is populated with the exception message. This is a dangerous technique since this data could often be very detailed and could give an attacker technical information about the system.

My suggestion for how to get around this involves using 2 techniques in cooperation.

a. First, for any exception in your application exception heirarchy, create member variables along the lines of userMessage and detailedMessage. ESAPI does this with their exception heirarchy, so you can browse their code for examples. The logic is that when these exceptions are created, they are created with very generic information for the user to see, and then the detailed information can be logged for admins to see. The user should only ever be presented with the generic message.

b. Second, for exceptions that don’t live in your application heirarchy (and even those that do in some cases), one should use a static very generic message to display on the screen for any security related issues. The example used above (using a different error message for a bad username and a good username/bad password – this tells the attacker the username is valid.) could be resolved by using a somewhat generic error to cover both errors, possibly “The user could not be logged in” or “Login failed”. This conveys the message to the user that the login failed, but doesn’t give specific information about why.

Note: One important point here is that this issue is a balancing act between user friendliness and security. It may save your users some frustration if they see that they’ve typed in the wrong username (honest mistake) rather than the wrong password, but that also gives an attacker opportunity. This decision, like most others must be considered in the context of your environment. My suggestion is to go with the more secure option by default, and only change if you absolutely must. Even then, you should consider putting additional protections in place, such as possibly using an ESAPI style application intrusion detection mechanism like AppSensor to track things like a user trying to login with many different usernames in a short period of time.

At this point, hopefully you’ve gotten a glimpse of how information leakage and improper error handling can negatively affect your application. Additionally, you’ve gained some insight on how to deal with exceptions and user messages properly. As mentioned before, there are various legitimate techniques that could be used, and the above is just one option.

Well, that’s all for this article – hope you’ve found it helpful. Let me know if you have any questions or suggestions.

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

Technorati Tags: , , , , , ,

← Previous PageNext Page →