John Melton's Weblog
Java, Security and Technology

Year Of Security for Java – Week 6 – CSRF Prevention in Java

No Gravatar

What is it and why should I care?
Cross Site Request Forgery (CSRF) is an attack wherein a victim is forced to execute unknown and/or undesired requests to a website at which he/she is currently authenticated. It exploits the fact that the “credentials” needed to perform a function on a website are generally loaded into a client-side cookie, which is transmitted automatically with every request. By exploiting this fact, an attacker can cause a victim to execute almost any request that isn’t protected against CSRF.

Here is a simple image that shows a basic CSRF attack. The steps are:
Step 1. The victim is lured to visit an evil site (evil.com)
Step 2. The victim’s browser loads the evil site, which contains a hidden image whose src points at an important transaction on good.com)
Step 3. The victim’s browser executes the transaction at good.com, passing along the session cookie (general authn/z mechanism).
Step 4. The transaction occurs, and the victim is not aware until later, if at all.

What should I do about it?
Now that we know what CSRF is and why it is dangerous, let’s consider some possible solutions.

Token
The classic solution to CSRF has been a per-session token (known as the synchronizer token design pattern). The basic flow is:
Step 1. User logs in and a randomized string (token) is placed in the user session
Step 2. On every form for a non-idempotent request (meaning essentially any request that changes server-side state – should be your HTTP POSTs), place the token in the form when it’s submitted.
Step 3. On the request handler for the non-idempotent request, validate that the submitted token matches the token stored in the session. If either is missing or they don’t match, do not process the transaction.

This solution has served pretty well for most situations over the years, but can be time-consuming to implement and often creates opportunities for forgetting validation on some requests.

The ESAPI project does have built in CSRF protection, but it is tied to the authentication scheme. Here is a writeup I previously did for ESAPI’s CSRF protection.

CSRFGuard
A very good option with solid protection is the OWASP CSRFGuard project. This library makes it relatively simple to include CSRF protection into your application by simply mapping a filter and updating a configuration file. This is certainly a resource worth checking out.

Stateless CSRF Protection
One more thing I’d like to point out is some interesting work John Wilander (@johnwilander) is doing in the area of stateless CSRF protection. In the case where you can’t or don’t want to maintain the user token in server-side session state, John proposes a seemingly novel solution. The proposal is to allow the client side to create a cookie with the CSRF token (which gets submitted on every request) and to include the token as a request parameter. Since an attacker can’t read both the cookie and request parameter, all the server side should have to do is validate that the token in the cookie and the request parameter match. This solution, to my knowledge, has not been widely reviewed or tested, but it is a great example of an elegant solution to a difficult problem. Only time will tell if this is the go-forward solution for stateless CSRF protection.

CSRF is a popular and dangerous attack, but with the protections described above, it is certainly manageable.

One last note here is that the token approach (classic or stateless) does break down when the site it is deployed on contains XSS (Cross Site Scripting) vulnerabilities. If an attacker can XSS your site, they can read the content and extract out the token you’re using, effectively nullifying the protection. The lesson is simple: fix those XSS bugs too!

References
———–
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
http://www.cgisecurity.com/csrf-faq.html
http://www.jtmelton.com/2010/05/16/the-owasp-top-ten-and-esapi-part-6-cross-site-request-forgery-csrf/
https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
https://www.owasp.org/index.php/Category:OWASP_CSRFGuard_Project

Technorati Tags: , , , , ,

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