The cross-site request forgery guard closes Intershop's vulnerability to cross-site request forgery attacks.
Cross site request forgery (CSRF)
A security token that is embedded into a web applications response and expected to be sent back by a browser upon subsequent requests.
A cross-site request forgery attack (CSRF for short, pronounced like sea-surf) is an attack which "forces an end user to execute unwanted actions on a web application in which he/she is currently authenticated." (Definition from OWASP)
The prerequisites for the attack are:
The attack is run like this:
1. A user authenticates at a login page. The session ID and authentication state are stored as cookies by his/her browser.
2. An attacker forges a URL and form parameters, if required, that has malicious side effects when requested by the authorized user.
3. The attacker sends the forged URL to the user via e-mail/chat/social media or on a website prepared by the attacker, making sure that the user is forced or tricked into sending a request to this URL.
4. The authorized user opens the e-mail/chat message or website and either his/her browser automatically issues the request or the user is tricked into triggering it. The browser includes session and authorization cookies into the request.
5. The request passes all authentication/authorization checks in the web application and proceeds to perform the malicious action.
Please note that the attack is blind, i.e., the attacker will not receive the web application response page – given no other security holes are exploited.
"According to the United States Department Of Homeland Security the most dangerous CSRF vulnerability ranks in at the 909th most dangerous software bug ever found, making this vulnerability more dangerous than most buffer overflows." (Quote from Wikipedia )
Also, it is considered number 5 of the Top 10 Web Application Security Risks for 2010 by the Open Web Application Security Project (OWASP).
In most configurations, Intershop fulfills all mentioned prerequisites and is vulnerable to this attack without taking counter measures.
It is not vulnerable if the session ID is configured to be a required part of every request's URL. (This can be achieved by setting
session.tracking.mode = URLOnly in the webadapter.properties.) However, besides usability problems, this increases vulnerability to other attacks, namely session hijacking.
In order to counter a CSRF attack, the strategy proven most effective OWASP Prevention Cheat Sheet is the synchronizer token pattern. In the absence of an attack it works as follows:
An attacker trying to run a CSRF attack on this web application will now fail because he cannot retrieve or guess the synchronizer token and the web application will thus reject to perform any forged requests.
Note that this countermeasure (like most others) is superseded by vulnerabilities to other kinds of attack, like cross-site scripting (XSS) and session fixation or session hijacking, or man-in-the-middle attacks (caused by unsecured transport).
The cross-site request forgery guard ("CSRFGuard" for short) is an implementation of the synchronizer token pattern, especially tailored for Intershop applications. It is not the equally named CSRFGuard by OWASP.
While different variations of the synchronizer token pattern exist and are in operation at various major websites, Intershop's CSRFGuard utilizes a POST only, single-instance synchronizer token.
At first, it is single-instance because a user session will get assigned a synchronizer token upon creation and use it for all responses until the session expires.
In contrast, other implementations generate a new synchronizer token for each response or each possible action that can be triggered from a response page which is only valid for this specific action. While this theoretically raises the barrier against CSRF attacks even higher, it requires storing multiple synchronizer tokens per session and associating them with actions. Since the number of valid synchronizer tokens has to be bounded, this can lead to usability issues: when a user tries to use a form from a response page that was generated non-recently and therefore its synchronizer token has expired, the request will be regarded as forged, will be rejected and trigger a false alert. On the other hand, a single synchronizer token per session provides an effective protection against CSRF.
The second special feature of Intershop's CSRFGuard is that it makes a distinction between requests that require CSRF protection and those that do not. For a request that does not require CSRF protection, the synchronizer token is not validated. This is necessary to avoid including the synchronizer token in the URL of a request, as this would result in two major flaws:
For these reasons, CSRFGuard only reads synchronizer tokens from HTTP POST parameters and a custom HTTP header.
As a result, there is a close correlation between HTTP methods and the question of whether they may cause side effects or not. The HTTP specification, for similar reasons, establishes the concept of "safe" methods RFC 2616 :
Implementors should be aware that the software represents the user in their interactions over the Internet, and should be careful to allow the user to be aware of any actions they might take which may have an unexpected significance to themselves or others.
In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested.
Please note that there are a few side effects that are allowed and unavoidable to be triggered by GET requests, like storing a list of recently viewed products, collecting statistical data or more intricate patterns, like lazily evaluating some calculation and caching its result. In accordance to the above notion, these exceptional side effects are called "safe".
A GET request is not allowed to have any unsafe side effects. In order to perform unsafe side effects, an HTML form/an HTTP POST request has to be implemented.
CSRFGuard now needs a notion to determine whether a request handler either
Hitherto there is no such distinction available. Pipeline start nodes have a call mode that states whether they are public or not, but not if they are reachable by HTTP GET or only by HTTP POST requests. Therefore, a mechanism is introduced to dynamically detect state changes. Only if such a state change occurs, the synchronizer token from the request will be validated against the one stored at the user session. If no state changes occur, no check will be performed.
StateChangeSafetyMgr is introduced whose purpose is to collect all occurring state changes and inform
StateChangeGuards about them. The
StateChangeSafetyMgr is implicitly context-aware. It will check from which context its methods are called (like which thread or which request). If needed, it will then determine which
StateChangeGuard is responsible for this context and ask it to check whether a state change is permitted or not.
CrossSiteRequestForgeryGuard is a special
StateChangeGuard that guards a single
Request object. When asked to check whether a state change is permitted, it will validate the synchronizer token from the request. If the token is missing or invalid, it will throw a
StateChangeSafetyMgr cannot fully detect changes in persistent state on its own, so it has to be informed by other parts of the system before a state change occurs. For this it comes with three methods:
This method has to be called whenever a state change is about to occur. It will throw a
Opens a safe changes block in the current thread. All calls to
Closes the current safe changes block, thus neutralizing the last call to
State changes inside a safe changes block are also called safe state changes. These are changes that are safe to execute even without a guard checking for permission, like the side effects that can still occur in GET requests. State changes outside safe changes blocks (they are the ordinary kind) are called "unsafe".
By using these three methods you may always override whether a change should be considered safe or not:
checkStateChangeAllowedineffective, enclose it in
checkStateChangeAllowedin front of it.
Please note that
endSafeChangesBlock always have to come in pairs. Especially, it is illegal to use a
startSafeChangesBlock call without a following
endSafeChangesBlock, as this would disable guarding for the rest of the thread, no matter what else might occur. They may however be nested. The level of nesting has no influence on what happens to
checkStateChangeAllowed calls inside the safe changes blocks: they will always pass.
Also note that none of the methods has parameters. Note especially that
checkStateChangeAllowed receives no input about the kind of state changes (like which persistent object is manipulated), either all changes of persistent state are currently allowed in a context or none.
To ease the usage of these methods, there are several ways to call them, from Java code, inside a pipeline or for each execution of a pipelet. See the Cookbook for details.
Besides the safe changes blocks above, CSRFGuard has a switch for enabling/disabling it on per request basis. For compatibility with legacy code it is disabled by default for custom Intershop applications. (It is shipped enabled for standard Intershop applications, like the back office and the demo storefront.) See the Cookbook on how to enable it.
To sum up, CSRFGuard will issue a CSRF alert and reject a request if and only if:
checkStateChangeAllowedhas occurred outside safe changes blocks.
StateChangeSafetyMgr comes with a heuristic that tries to detect a state change in a generic way:
checkStateChangeAllowed will be called whenever a transaction is opened, like by explicitly opening a database transaction in a pipeline, or implicitly by using a pipelet marked with the "transaction required flag" (capital T in Intershop Studio). A database transaction will imply unsafe state changes in most cases. For all others it can be marked a safe change by using safe changes blocks.
Also, there are a few other code artifacts that call
For batch processes/jobs the check is performed in the pipeline that triggers the job creation/scheduling – as every asynchronously running pipeline is called only for the sake of its state changes and all are considered unsafe. Inside an asynchronously running pipeline, all calls to
checkStateChangeAllowed will pass.
Unfortunately, this heuristic is not perfect for detecting all state changes and deciding whether they are unsafe or safe. The following cases require further refinement:
CSRFAttackAlertException is thrown but no attack was run. This is called a "false alert". With automatic token injection (see below) this will occur mostly when a state change is detected for an HTTP GET request. This can result in rendering a web application non-functional since the requested action is not performed and only a general error response will be delivered. See the Cookbook on how to cope with this.
An unsafe state change occurs but it is not detected and CSRFGuard does not validate the synchronizer token. This is called a "missing alert". This results in a security hole in the application, where it is not guarded against CSRF. Since this – other than false alerts – does not show up in logging or simple testing, care has to be taken to find these by investigating code or systematic penetration tests. For details again see the Cookbook.
As a special variant of missing alerts, there can also be late alerts. A "late alert" occurs if CSRFGuard successfully detects an attack and aborts request handling, but an unsafe change has already occurred. Besides database transactions there is no generic way of undoing changes.
Unfortunately, this issue can even slip through penetration tests. Therefore, it is important to call
To enable authorized users to pass CSRFGuard, the synchronizer token has to be injected into all forms that trigger security-relevant changes. For CSRFGuard it is inserted as hidden form field with a fixed name. The injection can either be performed automatically or manually.
To solve the problems that came up with the client side, a server-side token injection is supported. To this end, ISML provides a new ISML
<isform> tag, which should be used instead of the HTML
<form> tag. During compilation this tag will be replaced with a regular HTML
<form> tag and a hidden field for the synchronizer token. The token itself will be set by the Web Adapter when delivering the page. A new CSRFServlet handles the token generation and delivers it to the Web Adapter.
X-IS-PLACEHOLDER_CSRFHTTP header, which indicates that there are placeholders for CSRF tokens on the current page.
CSRFServletto determine the CSRF tokens and injects them into the appropriate
Client-side injection also uses the fact that the browser has to come up with a parsed representation of the page while the web application – like Intershop 7 – usually does not. Attempts to cover all forms automatically at server side are thus doomed to either fail or drain considerable server performance.
To see how to enable automatic token injection also refer to the Cookbook.
While this seems tedious and error-prone, missing a form will never cause a security breach. The validation of synchronizer tokens is still generically performed. Instead, it may cause a false alert.
The information provided in the Knowledge Base may not be applicable to all systems and situations. Intershop Communications will not be liable to any party for any direct or indirect damages resulting from the use of the Customer Support section of the Intershop Corporate Web site, including, without limitation, any lost profits, business interruption, loss of programs or other data on your information handling system.