John Melton's Weblog
Java, Security and Technology

The OWASP Top Ten and ESAPI – Part 5 – Cross Site Request Forgery (CSRF)

No Gravatar

This article will describe how to protect your J2EE application from Cross Site Request Forgery (CSRF/XSRF) attacks using ESAPI. 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 is Cross Site Request Forgery (CSRF)? As usual, let’s check in with what OWASP says it is:

“A CSRF attack forces a logged-on victim’s browser to send a request to a vulnerable web application, which then performs the chosen action on behalf of the victim. The malicious code is often not on the attacked site. This is why it is called ‘Cross Site’. ” [from here] Additionally, they give several examples of the types of vulnerable sites including sites that “Authorize requests based only on credentials that are automatically submitted such as the session cookie if currently logged into the application, or ‘Remember me’ functionality if not logged into the application, or a Kerberos token if part of an Intranet participating in integrated logon with Active Directory”. Finally this statement is added: “Unfortunately, today, most web applications rely solely on automatically submitted credentials such as session cookies, basic authentication credentials, source IP addresses, SSL certificates, or Windows domain credentials.”

So, what does all this mean? It means that (most likely) if you aren’t protecting against CSRF, you are vulnerable to it. That’s a scary thought! Many developers don’t even know about the attack (though they should), yet they are vulnerable by default in many instances. It’s a devastating attack to many web applications. Let’s discuss in a bit of detail what it looks like. In my opinion, the easiest way to explain the attack is to walk through it in a series of steps.

1. Bob (User/Victim) logs in (or is already logged in) to “Vulnerable website X”. This website has contains some sort of e-commerce type functionality. It also allows you to store your credit card for future purchases.
2. Mary (Attacker) knows and uses website X and realizes that CSRF is a vulnerability in the application.
3. Mary crafts a bit of html and/or javascript and posts it to a forum/message board that Bob reads (any site on the internet).
The code might look something like this:


<img src="http://www.siteX.com/completePurchase.do?itemId=ABC123" />


4. Bob views the html and/or javascript by visiting the forum (though nothing visible shows up) and the code is executed. Bob has just purchased an item of the attacker's choosing without knowing it.

Ok, a few things to note about the sequence above.
a. The vulnerable site doesn't have to be e-commerce. It could be credit card related info, or adding a friend to your group. For the most part, it has to do with transactions. Usually, it's not a big deal on "view" type pages.
b. The forum/message board, while common, is not the only way to cause this. It could be done through an email, or any other number of attack vectors.
c. The actual attack here was fairly benign, but be certain, there are more nefarious attacks that exist, and are executed all the time.

Ok, so hopefully you are sufficiently concerned now based on the description above.

Where do we go from here? ....

So, now we understand what can happen if a site is vulnerable to CSRF (and most are), but what how do we solve that problem. Well, simply put, we have to have a way to know that the request is legitimate, meaning that the user intended to make the request. The most common mechanism in place today (that works) is the token. The token is a generic term that is used for implementations of the "synchronizer token pattern". There are several working implementations that use the token today, including Struts 1 and 2, Webwork, SpringMVC, and even OWASP's own CSRFGuard Project. However, since we're discussing the usage of ESAPI to solve the OWASP Top Ten, we'll cover how ESAPI does it in this article.

At this point, CSRF is actually pretty easy to solve. We know what the issue is, know how to solve it, and have a framework (ESAPI) that will help with the specifics. So, here are the steps we'll actually go through in order to protect our apps from CSRF attacks.
1. Generate new CSRF token and add it to user once on login and store user in http session.
2. On any forms or urls that should be protected, add the token as a parameter / hidden field.
3. On the server side for those protected actions, check that the submitted token matches the token from the user object in the session. (Assuming you've implemented this properly, a failure constitutes a security issue.)
4. On logout and session timeout, the user object is removed from the session and the session destroyed.

Now that we have the steps, we'll give a short snippet of code that shows each in action.

Step 1. Generate new CSRF token and add it to user once on login and store user in http session.
This code should be executed when the user logs into the application. This is done in the default ESAPI implementation, and it is stored as a member variable of the User object that gets stored in the session.


//this code is in the DefaultUser implementation of ESAPI

/** This user's CSRF token. */

private String csrfToken = resetCSRFToken();

...
public String resetCSRFToken() {

	csrfToken = ESAPI.randomizer().getRandomString(8, DefaultEncoder.CHAR_ALPHANUMERICS);

	return csrfToken;

}

Step 2. On any forms or urls that should be protected, add the token as a parameter / hidden field.
The addCSRFToken method below should be called for any url that is going to be rendered that needs CSRF protection. Alternatively if you are creating a form, or have another technique of rendering URLs (like c:url), then be sure to add a parameter or hidden field with the name "ctoken" and the value of DefaultHTTPUtilities.getCSRFToken(). That should do the work of adding the data to the url or form. We'll validate it in the next step.


//from HTTPUtilitiles interface
final static String CSRF_TOKEN_NAME = "ctoken";

//this code is from the DefaultHTTPUtilities implementation in ESAPI

public String addCSRFToken(String href) {

	User user = ESAPI.authenticator().getCurrentUser();

	if (user.isAnonymous()) {

		return href;

	}

	// if there are already parameters append with &, otherwise append with ?

	String token = CSRF_TOKEN_NAME + "=" + user.getCSRFToken();

	return href.indexOf( '?') != -1 ? href + "&" + token : href + "?" + token;

}

...

public String getCSRFToken() {

	User user = ESAPI.authenticator().getCurrentUser();

	if (user == null) return null;

	return user.getCSRFToken();

}

Step 3. On the server side for those protected actions, check that the submitted token matches the token from the user object in the session. (Assuming you've implemented this properly, a failure constitutes a security issue.)
Ensure that you call this method from your servlet or struts action or jsf controller, or whatever server side mechanism you're using to handle requests. This should be called on any request that you need to validate for CSRF protection. Notice that when the tokens do not match, it's considered a possible forged request.


//this code is from the DefaultHTTPUtilities implementation in ESAPI

public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException {

	User user = ESAPI.authenticator().getCurrentUser();

	// check if user authenticated with this request - no CSRF protection required

	if( request.getAttribute(user.getCSRFToken()) != null ) {

		return;

	}

	String token = request.getParameter(CSRF_TOKEN_NAME);

	if ( !user.getCSRFToken().equals( token ) ) {

		throw new IntrusionException("Authentication failed", "Possibly forged HTTP request without proper CSRF token detected");

	}

}

Step 4. On logout and session timeout, the user object is removed from the session and the session destroyed.
In this step, logout is called. When that happens, note that the session is invalidated and the current user object is reset to be an anonymous user, thereby removing the reference to the current user and accordingly the csrf token.


//this code is in the DefaultUser implementation of ESAPI

public void logout() {

	ESAPI.httpUtilities().killCookie( ESAPI.currentRequest(), ESAPI.currentResponse(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME );

	HttpSession session = ESAPI.currentRequest().getSession(false);

	if (session != null) {

		removeSession(session);

		session.invalidate();

	}

	ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(), ESAPI.currentResponse(), "JSESSIONID");

	loggedIn = false;

	logger.info(Logger.SECURITY_SUCCESS, "Logout successful" );

	ESAPI.authenticator().setCurrentUser(User.ANONYMOUS);

}

So there you have it. Not very complex, but solid protection against CSRF. In quick review, we covered what CSRF is, why it's a problem, and how to solve it using 4 simple steps (create token, add token to forms/urls, verify token server side, kill token on logout). There are a couple of additional notes I wanted to point out.

Note: In addition to resolving the CSRF issues in your application, you also need to resolve the XSS issues in your application (see The OWASP Top Ten and ESAPI - Part 2 - Cross Site Scripting (XSS)). If those still exist, the CSRF defenses can be circumvented.

For some additional background and information on CSRF, see the OWASP CSRF Prevention Cheat Sheet.

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 CSRF and if you've seen it as a large problem for your applications.

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 4 – Insecure Direct Object Reference

No Gravatar

This article will describe how to protect your J2EE application from direct object reference (DOR) attacks using ESAPI. 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 is direct object reference (DOR)? Other than being a somewhat quirky, generic name … here’s what OWASP says it is:

“A direct object reference occurs when a developer exposes a reference to an internal implementation object, such as a file, directory, database record, or key, as a URL or form parameter. An attacker can manipulate direct object references to access other objects without authorization, unless an access control check is in place. ” [from here]

So, what does that mean? Well for most (not all) J2EE developers, it will mean database key references, so that’s what we’ll deal with here. However, the discussion is applicable no matter what your reference.

Consider the following database table called USERS.

ID FNAME LNAME
1 John Melton
2 Bill Smith
3 Susan Thomas
4 David Carter

Now, let’s say that this database table were queried in a normal application. Then, the results are presented on the page, and each record in the result list would probably have a link to more detail about each user, having their pictures, their list of friends, etc. This is the typical master-detail interaction and is prevalent in pretty much any web app, not just J2EE. But how do we get to the detail page? How do we pass along which user we want to see in detail from the “master” table to “detail” page? Well, we could start by using the first name, but that’s not unique, or we could use the last name, but same issue. We could include both, which is less likely to produce duplicates but it’s still possible. In most situations, what happens is each table in the database has a column setup as a unique identifier. Each record in the table will have a different ID. So, that’s what we use. Now, here’s what the url might look like to go view greater detail about Bill:

/users/viewDetail?id=2

Ok, great, so what we have is the identifier being passed in the url to represent Bill. That way when we get to the view detail code, we simply check the id that was passed in and pull up that record in detail and display the information.

So where’s the issue? Well, everything works fine in this instance b/c every user is able to see the detail, but let’s look at what this might look like for a bank, which is the classic DOR example. In a bank, all records for all users are stored in the same table (at least in our example), however each user can only view his or her account. They should not be able to simply pick a random account to view or manipulate. But what if the URL to my account looks like:

/accounts/viewDetail?id=3540

What would happen if I changed this to

/accounts/viewDetail?id=3541

If there’s no protection in place, I can see someone else’s account!

Well, this is the crux of the DOR problem. Any attacker can manipulate url or form parameters at will when they submit a request, which means this issue obviously applies to both GET and POST requests, as well as exposed parameters, hidden fields, etc. If it’s being sent from the client to the server, the client can alter it. That means when you use the ID as the reference, and that ID can be manipulated, the attacker can gain access to data that they should not have access to. The ID in this case is the direct reference (id) to the object (record in the table) that you are trying to access.

Where do we go from here? ….

Well, ok, that’s not super encouraging. We have an issue (that most people have never heard of) that is affecting most applications . Banking is the obvious example, but this could be a problem for many different types of applications. Take heart, there is a solution (actually there are two)! You have 2 options for how to properly deal with this issue when it exists in your application.

1. Use ESAPI’s AccessReferenceMap (or something similar)
2. Perform authorization on the view detail page
Bonus. Use both! (the only way to go for paranoid people like me)

Let’s discuss the basic concepts of each of the options.

AccessReferenceMap

The AccessReferenceMap is an interface for a map which has methods that allow you to add a “direct” reference (which generates an “indirect” reference), then retrieve an indirect reference using a direct reference, or retrieve a direct reference using an indirect reference.

Confused yet? Me too. Actually it’s quite simple. Let’s use a contrived (and insecure) example just to illustrate the concept (again, this simplified version is NOT secure).

Let’s say you have a table in the database with 4 records, and their id’s are 1,2,3,4. Now let’s say you have the situation above where you display all these records in a master table, and each row is a link to more detail about the individual record. Let’s say you want to hide these numbers and reference them on the UI as letters instead. The simple mapping would be 1=A, 2=B, etc… In this case, when you retrieve the data from the database, your ids are 1,2,3,4. However, when you show them on the screen, their ids are A,B,C,D. Finally from the detail page (after the user clicks the link), you would just lookup what C matches, find that it is 3, then retrieve that record from the DB and display it. It’s that simple.

Now, in practice, obviously a letter -> number matrix is too simple to be effective. What works better, as usual in computer science, is randomness. That’s why ESAPI already contains a class called RandomAccessReferenceMap. Here’s an example of how you might use it.


MyObject obj;	 	// generate your object
Collection coll; 	// holds objects for display in UI

//create ESAPI random access reference map
AccessReferenceMap map = new RandomAccessReferenceMap();

//get indirect reference using direct reference as seed input
String indirectReference = map.addDirectReference(obj.getId());

//set indirect reference for each object - requires your app object to have this method
obj.setIndirectReference(indirectReference);

//add object to display collection
coll.add(obj);

//store collection in request/session and forward to UI
...

As you can see the code is fairly simple. Beyond this, the only other code is when it is displayed on screen, you use the indirect reference to be the id that gets you to the view detail page. From the view detail page, you retrieve the id that was passed in, then iterate over the collection in memory until you find the object from the map matching the indirect reference and then retrieve the full data from the DB by mapping back to the original ID.

A couple notes here:
- If you get an id passed in that doesn’t match any in your collection, it means either the code is wrong, or the user has tampered with it, so it should be a security issue
- You’ll note my object has a method called setIndirectReference. All my value objects in my applications extend a base class with some helper methods, and this is one of them. This is obviously not required and there are many ways to accomplish the usage of the RandomAccessReferenceMap, but I build my apps knowing I’m going to use this technique, so it’s not a problem for me.

Per-Page Authorization

Per page authorization is another technique that has a similar goal to the AccessReferenceMap. The idea here is that you’ve already done the appropriate authorization on the master page. Again, for simplicity, let’s use the bank account example. Let’s say you have a checking and savings account with a particular bank, and both of those accounts show up on your “master” accounts page. The code has to check what you have access to (authorization) in order to only display the appropriate 2 accounts to you on that page.

Unfortunately, that’s where many applications stop. They assume since they’ve only given you 2 accounts to choose from, you’ll have to choose 1 of the 2. This doesn’t take tampering into account, however, and tampering can allow the attacker to input any account they choose.

What the per-page authorization says is that if and when the attacker tampers with the data sent to the detail page, it still shouldn’t be possible for him to see data that is not his. The code that brings up detail about a specific account should first include a check that you have access to that account (authorization). Again, if he doesn’t have access to that account, either the code is broken, or he is tampering and that is a security incident.

So, which option should I choose

Well, either or both. They are both viable options to solve the DOR problem, but I’ll try to give a couple of points about both that may sway you one direction or the other.

AccessReferenceMap
1. *May* not require an extra DB hit to do detail page authorization – depends on how you’ve coded it.
2. Shields actual IDs from end user. In case you ever have a vulnerability on another page, and haven’t protected for it properly, the attacker won’t know your IDs.
3. Requires a bit of extra coding and some extra information to pass around the application in order to maintain access to the reference maps.
4. Currently not very popular, so not very well understood yet.

Per-Page Authorization
1. *May* require an extra DB hit to do detail page authorization – depends on how you’ve coded it.
2. Exposes actual IDs from end user. In case you ever have a vulnerability on another page, and haven’t protected for it properly, the attacker could know your IDs.
3. Doesn’t requires extra coding or the passing of information around the application in order to maintain access to the reference maps.
4. Very well understood paradigm.

Well, there you have it. There’s really not that much to it. While direct object access is a significant issue in many of today’s applications, it can be fairly simply corrected. I’ve presented a couple of options that can be done separately or combined together as a solution. I like to use them both, but separately, they still do their job properly.

Just one final safety note. While I’ve only discussed these techniques in the context of database queries, whichever one or both that you choose should additionally be applied when referencing any sensitive internal resources, including files, internal objects, classes, etc.

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

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 3 – Malicious File Execution

No Gravatar

This article will describe how to protect your J2EE application from malicious file execution attacks using ESAPI. 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?

So what exactly is malicious file execution? It could mean different things to different people. Here, I want to limit the discussion to the execution, either immediate or delayed, of files or file handles that can be manipulated in some way by user input. This is a fairly broad definition that can cover a few different situations. Let’s first discuss a few of the different types of issues that can come up. This collection is by no means exhaustive, but should give us decent coverage of the types of issues that arise when dealing with file input.

1. Included file name is partially or wholly determined by dynamic input (think dynamic include files)
2. File is uploaded and written to disk with “as is” (no validation of uploaded file – just write to disk)
3. File name to display or retrieve is partially or wholly determined by dynamic input
4. Command / data file is uploaded (think a batch process being kicked off with data from an uploaded spreadsheet)

So, what types of issues do these particular situations present us with. In general, an attacker can manipulate this process to gain increased privileges, access data for which they are not authorized and even execute code. Since these aren’t the only 4 examples of issues that exist, we won’t specifically delve into each issue in detail, but we’ll try to extract some common problems that are present in one or more of the scenarios listed above. This set of problems is related to common file upload / processing situations.

1. Missing or insufficient input validation – This is almost always true with file processing. This also is a broad topic, since it deals both with the file name and path, as well as the file contents. Many times, this could express itself as uploading a file as is and simply writing it out with a filename that is either the name of the file as uploaded, or a name specified by the user. This could cause issues like directory traversal (“../../etc/passwd” – overwriting the passwd file – sorry for the old cliche example), or overwriting other files in the filesystem (“../../jsps/login.jsp” – overwriting the login page). Something like this could allow the attacker to break the site significantly up to and including owning the site, and even the server it’s hosted on. While most file processing code I’ve seen is not bad enough to allow something like this, some of it is just that bad .. scary.

2. No virus scanning – This goes along with input validation to some extent, but if you are uploading a file that is going to be executed in any way at any time, it should be virus scanned. There are engines out there, even free ones, that you can call out to in order to scan the file. If the scan fails, the file should be deleted, and the incident should be logged as a security incident. At that point, the normal security incident response process in your organization can be executed.

3. No size checks – One of the simplest tasks you can perform that is often overlooked is to check the file size of the uploaded file. There is most likely a reasonable limit to the size of your accepted files. For instance, a spreadsheet would have to have quite a bit of data to be any more than a few MB, but an attacker could upload files of many times more than that to try and fill up the file system, or just hang processing on the server to block out other valid users.

4. Invalid file type processing – This task is a bit more difficult, but makes sense in many cases. If you are an image hosting site, there’s no reason to accept Word files. This should involve creating a whitelist of the types of files you will accept and then verifying that only those are uploaded. This does NOT mean file extension checks. Although these can be used as a superficial first test, they are trivial to change and provide no security assurance. Often times, this check will involve output encoding (see #7).

5. Giving too much control over file name input – This occurs when users are allowed to influence the final filename that is output to the filesystem. This could happen by allowing a user to type in the desired filename or by just accepting their filename and using that on the server side. However, it is much safer to generate the filename that is used to save the file to the filesystem. Generally, this would have some securely random string of characters, as well as the author, date, time, etc. If there is a specific requirement to accept input from the user as to what the filename should be, just ensure that the name given is validated against an acceptable whitelist before writing the file out.

6. Direct object reference (DOR) problems – While the DOR issue affects more than just filenames, it is relevant here so we’ll quickly discuss it. DOR is simply an issue where the actual filename is pointed to directly. This filename could be in a hidden field, stored in a cookie, or some other place that is not directly seen by the user on the screen. Typically the filename is taken directly and used to retrieve or execute the file. This could cause issues of broken authorization (attacker changes filename to access another user’s file), elevation of privileges (touching a file belonging to a user with higher privileges or the system user), or many other problems. This topic is covered in greater detail in the next article in the series.

7. No output encoding – This issue doesn’t always exist since not every filetype can be thought of in this way. The basic issue is when a file is not validated properly before being written out. There are several filetypes that are valid, that could have extra information in them. However, of those, there are some file types which can be read in, and then written out again to ensure the “bad stuff” is not still there. This does not apply to all “bad stuff” that can be contained in those files, nor does it apply to every file type, but it can be useful when the option is available, though it rarely if ever is used in many applications.

8. Not authorizing access – This issue exists because many applications contain reasonably appropriate authentication, but horrible if any authorization. Once a user is authenticated, many times they can perform any function in the application. The classic example of this is not restricting access to a certain page, let’s say the admin screen. The home page might not show the link, but if they type the link into the url bar, there’s nothing stopping them from getting there. Depending on the type of site, this could be especially harmful with file upload. Often times, only “trusted” people are expected to be able to upload files, but if the authorization is broken, it could allow anyone to upload files at will. Again, this depends on the type of site you have – it may be perfectly fine for everyone to upload files (like flickr or youtube).

Where do we go from here? ….

So, we’ve discussed lots of issues that can crop up when dealing with uploading files, so how does ESAPI and general best practices say we should deal with these issues? Let’s take them one by one.

1. Missing or insufficient input validation – As discussed in part 2 of this series, ESAPI makes it fairly simple to do proper input validation through the framework. The code is very simple, and extensible through the addition of new regular expressions. Here is an example of how ESAPI checks the filename of the uploaded file to verify that it is valid.


if (!ESAPI.validator().isValidFileName("upload", filename, allowedExtensions, false)) {
	throw new ValidationUploadException("Upload only simple filenames with the following extensions " + allowedExtensions, "Upload failed isValidFileName check");

}

2. No virus scanning – ESAPI does not directly support virus scanning through the base APIs, but several of the antivirus vendors support API access for Java. I’ve heard that there are also free AV tools that offer this feature as well.

3. No size checks – There is no built in support for this in ESAPI. However, several of the web frameworks do provide support for this. Additionally, most if not all file upload libraries also provide support for this. Lastly, it’s trivial to perform your own check even if your specific library does not support it directly. Just load the uploaded file into a file object and call the length() method on it to determine the size of the file in bytes. Here is what ESAPI uses to prevent large files. The following is a snippet:


ServletFileUpload upload = new ServletFileUpload(factory);

upload.setSizeMax(maxBytes);

4. Invalid file type processing – This task is supported by the input validation portion of ESAPI again. First, the filename could be validated by the application. Then, each input from the file that is processed could again be validated by the application. Think of processing a spreadsheet. The filename should first be tested, then not only each line, but each cell should be checked for validity before being used by the application.

5. Giving too much control over file name input – In order to at least partially solve this issue, ESAPI has the SafeFile object. This is a trivial extension to the java.io.File object that additionally performs checks of the file and directory names to check for unsafe characters. However, this is a blacklist check. It is likely that you could do a better job if you know what characters are allowed in your filenames and only allow those (whitelist), though the characters in the ESAPI blacklist should minimally be disallowed.

6. Direct object reference (DOR) problems – Again, this will be covered in greater detail in the next article, but here I will just mention that ESAPI does have a mechanism to hide DORs. This involves essentially creating a map of direct -> indirect references and then using the indirect references for display, then mapping back during the processing. Come back for the next article for more details on how this is actually done in code.

7. No output encoding – There is no built in support for this in ESAPI. However, there are ways of doing this that *may* work for different filetypes. The most obvious one is images. If an image is uploaded, you can open the file, load the contents into an image object, then save that object. This guarantees that the image is a valid object. Otherwise, loading the image will fail. (Note: this is the expected behavior, though there have been some defects that may cause this not to work – ensure your library version functions correctly here). It may also be possible to do this with the help of some 3rd party libraries depending on the file type you are processing.

8. Not authorizing access – ESAPI does have authorization coverage in the framework, but it deserves its’ own discussion. Actually, the last article in this series will cover restricting URL access which will discuss the authorization capabilities of ESAPI. Additionally, CSRF (Cross Site Request Forgery) protections can help deal with this issue as well, and this is also going to be covered in a later article in the series.

I’d like to mention a couple of other helpful things that are more systems management related when dealing with uploaded files.

- Use a safe base directory when saving your uploaded files that is outside the standard web directory that your site is served from. This will force your application to be the only thing that can access these files. That way, an attacker can’t drop a file in an accessible directory.

- Use the file-system access controls that are offered in your operating system and possibly your web/application server. Ensure that only the appropriate users have privileges and that they have the least privilege necessary to do their jobs. This is a necessary stopgap in case your other protections fail.

- Audit properly. This can’t be stressed enough. If you audit and log properly, and then *READ* those logs, then you can notice when strange behavior occurs. This can help you locate things that need to be resolved.

Hopefully this article has been useful in helping you recognize the types of issues related to file upload and some best practices for dealing with those. As in all the other articles, I recommend trying to be as safe as possible, and only having your app do what is necessary. If you don’t need to upload files, don’t do it. If you have to do it, spend time making sure it’s as safe as you can make it. Let me know if you have other suggestions or best practices you use with file upload.

Editorial Note: I realize it’s been quite a while since I posted any articles in this series. However, I plan to finish up the series in the next few months by posting an article every week or two now that I can spend a bit more time on it. I also realize that in the gap of time I had off, the new OWASP Top Ten (2010) has been released and it supercedes the 2007 list. However, all the issues in the 2007 list either still exist in the 2010 list, are covered by it, or are still issues that may not make that high of a ranking anymore, but are still important. For these reasons, and the fact that I’d already started using the 2007 list, I’ll finish up with the 2007 list. I may go back at the end and catch any new ones from the 2010 list if relevant.

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: , , , , , ,