The core idea of our new countermeasure is the following: client-side state (i.e. session cookie headers and authentication headers) is stripped from all cross-origin requests, except for expected requests. A cross-origin request from origin A to B is expected if B previously (earlier in the browsing session) delegated to A. We say that B delegates to A if B either issues a POST request to A or if B redirects to A using a URI that contains parameters.
The rationale behind this core idea is that (1) non-malicious collaboration scenarios follow this pattern, and (2) it is hard for an attacker to trick A into delegating to a site of the attacker: forcing A to do a POST or parametrized redirect to an evil site E requires the attacker to either identify a cross-site scripting (XSS) vulnerability in A or to break into A’s Webserver. In both these cases, A has more serious problems than CSRF. Obviously, a GET request from A to B is not considered a delegation, as it is very common for sites to issue GET requests to other sites, and it is easy for an attacker to trick A into issuing such a GET request.
Unfortunately, the elaboration of this simple core idea is complicated somewhat by the existence of HTTP redirects. A Web server can respond to a request with a redirect response, indicating to the browser that it should resend the request elsewhere, for instance, because the requested resource was moved. The browser will follow the redirect automatically, without user intervention. Redirects are used widely and for a variety of purposes, so we cannot ignore them. For instance, both non-malicious scenarios heavily depend on the use of redirects. In addition, attacker-controlled Websites can also use redirects in an attempt to bypass client-side CSRF protection.
Hence, correctly dealing with redirects is a key requirement for security. The flowgraph summarizes the filtering algorithm. For a given request, it determines what session state (cookies and authentication headers) the browser should attach to the request. The algorithm differentiates between simple requests and requests that are the result of a redirect.
Simple Requests. Simple requests that are not cross-origin, as well as expected cross-origin requests, are handled as unprotected browsers handle them today. The browser automatically attaches the last known client-side state associated with the destination origin (point 1). The browser does not attach any state to non-expected cross-origin requests (point 3).
Redirect Requests. If a request is the consequence of a redirect response, then the algorithm determines if the redirect points to the origin where the response came from. If this is the case, the client-side state for the new request is limited to the client-side state known to the previous request (i.e. the request that triggered this redirect) (point 2). If the redirect points to another origin, then, depending on whether this cross-origin request is expected or not, it either gets session-state automatically attached (point 1) or not (point 3).
When Is a Request Expected? A key element of the algorithm is determining whether a request is expected or not. As discussed above, the intuition is: a cross-origin request from B to A is expected if and only if A first delegated to B by issuing a POST request to B, or by a parametrized redirect to B. Our algorithm stores such trusted delegations, and an assumption that we rely on (and that we refer to as the trusted-delegation assumption) is that sites will only perform such delegations to sites that they trust. In other words, site A remains vulnerable to CSRF attacks from origins to which it delegates. The algorithm to decide whether a request is expected goes as follows. For a simple cross-origin request from site B to site A, a trusted delegation from site A to B needs to be present in the delegation store.
For a redirect request that redirects a request to origin Y (light gray) to another origin Z (dark gray) in a browsing context associated with some origin α, the following rules apply.
- First, if the destination (Z) equals the source (i.e. α = Z), then the request is expected if there is a trusted delegation from Z to Y in the delegation store. Indeed, Y is effectively doing a cross-origin request to Z by redirecting to Z. Since the browsing context has the same origin as the destination, it can be expected not to manipulate redirect requests to misrepresent source origins of redirects (cfr next case).
- Alternatively, if the destination (Z) is not equal to the source (i.e. α 6 = Z), then the request is expected if there is a trusted delegation from Z to Y in the delegation store, since Y is effectively doing a crossorigin request to Z. Now, the browsing context might misrepresent source origins of redirects by including additional redirect hops (origin X (white). Hence, our decision to classify the request does not involve X.
Finally, our algorithm imposes that expected cross-origin requests can only use the GET method and that only two origins can be involved in the request chain. These restrictions limit the potential power an attacker might have, even if the attacker successfully deceives the trusted-delegation mechanism. Mapping to Scenarios. The reader can easily check that the algorithm blocks the attack scenarios from Section 3.2, and supports the non-malicious scenarios from that section. We discuss two of them in more detail.
In the PayPal scenario, step 13 needs to re-use the state already established in step 2, which means that according to the algorithm, the request from PayPal to A should be expected. A trusted delegation happens in step 2, where a cross-origin POST is sent from origin A to PayPal. Hence the GET request in step 13 is considered expected and can use the state associated with origin A. Also, note how the algorithm maintains the established session with PayPal throughout the scenario. The session is first established in step 3. Step 4 can use this session because the redirect is an internal redirect on the PayPal origin. Step 8 can use the last known state for the PayPal origin and step 10 is yet another internal redirect.
In the link injection attack, the attack happens in step 13 and is launched from origin E to site A. In this scenario, an explicit link between A and E exists because of the link injected by the attacker. This link is however not a POST or parametrized redirect, so it is not a trusted delegation. This means that the request in step 10 is not considered to be expected, so it cannot access the previously established client-side state, and the attack is mitigated.