Best Practices - Cross-Site Request Forgery

Cross-Site Request Forgery

Vulnerability Overview

Cross-Site Request Forgery or CSRF (CWE-352) is an attack that occurs when the web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent HTTP request was intentionally provided by the user who submitted the request.

A CSRF attack works because browser requests automatically include all cookies including session cookies. Therefore, if the user is authenticated to the site, the site cannot distinguish between legitimate requests and forged requests.

The flaw occurs when the application does not have any mechanism to distinguish between legitimate requests and forged requests.

Recommended Security Controls

According to the OWASP​ and ​MITRE​ recommendations, there are a few approaches to mitigate CSRF attacks. Each of these approaches is suitable for specific types of web applications.

The most commonly used and recommended solution is via the ​Synchronizer Token Pattern​. Using this security control, CSRF tokens are generated on the server-side. They can be generated once per user session or for each request. Per-request tokens are more secure than per-session tokens as the time range for an attacker to exploit the stolen tokens is minimal. However, this may result in usability concerns. For example, the "Back" button browser capability is often hindered as the previous page may contain a token that is no longer valid. Interaction with this previous page will result in a CSRF false positive security event at the server. In per-session token implementation after initial generation of a token, the value is stored in the session and is used for each subsequent request until the session expires.

When an HTTP request is issued by the client, the server-side component must verify the existence and validity of the token in the request compared to the token found in the user session. If the token was not found within the request, or the value provided does not match the value within the user session, then the request should be aborted, the user session terminated and the event logged as a potential CSRF attack in progress.

CSRF tokens prevent CSRF attacks because without knowing the correct CSRF token, attackers cannot create valid HTTP requests to the backend server.

Another security control is the validation of the HTTP request’s origin via standard HTTP request headers​. There are two steps to this mitigation, both of which rely on examining an HTTP request header value:

  1. Determining the origin the request is coming from (source origin) which can be achieved via Origin or Referer headers.

  2. Determining the origin the request is going to (target origin).

On the server side, if both are verified as matching, the request is accepted as legitimate (meaning it's the same origin request) and if not we discard the request (meaning that the request originated from cross-domain). Such headers are deemed reliable and trustworthy as they cannot be altered programmatically (using JavaScript with an XSS vulnerability) since they fall under the forbidden headers list, meaning that only the browser can set them.

How Waratek’s Protection Works

Waratek offers protection against CSRF attacks via 2 different features in the ARMR http rule:

  1. csrf(synchronized-tokens)

  2. csrf(same-origin)

Users can enable either one of these features or both. OWASP recommends using both security controls, however not all application environments are applicable for both types of security controls.

The CSRF Synchronizer Token Pattern (STP) rule

At a high-level, the CSRF STP rule stops the processing of the JSP/Servlet if the received HTTP request is missing or carries an incorrect CSRF token.

The CSRF STP rule enables the Synchronizer Token Pattern protection, which instructs Waratek to inject CSRF tokens in specific HTML elements. The HTML elements covered are:

  • <form>​ elements in which the token is injected as a hidden input field.

  • <a>​ elements in which the token is injected in the URL specified by its href attribute.

  • <frame>​ and <iframe>​ elements in which the token is injected in the URL specified by their src attributes.

Enabling the default CSRF STP rule ensures all HTTP POST requests will be protected by validating the CSRF token present in the requests. HTTP POST requests are the most important types of requests to protect because they are typically state-changing, whereas HTTP GET requests are typically not.

Using the configuration of this rule, users have the option to:

  • Enable protection for HTTP GET requests

    • By default only HTTP POST requests are protected. If protection for HTTP GET requests is also required, use the method option:​ csrf(synchronized-tokens, options: {method: [GET, POST]})​.

  • Exclude / whitelist specific HTTP endpoints from protection

    • By default all HTTP endpoints are protected. If protection for specific HTTP endpoints must be disabled use the exclude option: csrf(synchronized-tokens, options: {exclude: ["/myApplication/safe.jsp"]}).

  • Exclude AJAX requests from protection

    • AJAX requests are not supported by the CSRF STP rule because the CSRF token is not injected into client-side Javascript code that generates dynamic requests such as AJAX. AJAX requests typically carry the X-Requested-With header. If the application uses AJAX requests, the ajax option can be used to disable validation for these requests: csrf(synchronized-tokens, options: {ajax: no-validate})​.

  • Use a different CSRF token for each HTTP method (POST / GET)

    • By default one CSRF token is used for POST requests and a different CSRF token is used for GET requests. The benefit of this is to protect the CSRF token for POST requests in case the CSRF token for GET requests gets leaked. The token-type option can be used to disable this and use a single token across both POST and GET requests instead: csrf(synchronized-tokens, options: {method: [GET, POST], token-type: shared}).

  • Rename the CSRF token used in the HTTP requests

    • By default the name of the CSRF token used by Waratek is “_X-CSRF-TOKEN”. In the rare case where this name is used by a different HTTP parameter, then use the token-name​ option to rename the HTTP parameter that Waratek uses to carry the CSRF token: csrf(synchronized-tokens, options: {token-name: "custom-name"}).

The CSRF Same-Origins ARMR rule

At a high-level, the CSRF Same-Origins rule checks if the received HTTP request is coming from a source origin different from the target origin. The source origin is determined by the Origin, Referer, or​ X-Forwarded-For headers. The target origin is determined by the Host or X-Forwarded-Host​ headers or by the hosts configured in the ARMR rule.

If the origin validation fails then the rule strips out all HTTP parameters, cookies and payloads from the HTTP request, rendering it harmless. If none of the Origin headers are present, the origin validation cannot be performed and the rule blocks the HTTP request, according to the OWASP recommendations. When enabling the default CSRF Same-Origins rule then all HTTP POST requests will be protected by validating the standard Origin HTTP response headers that should be present in the requests. Following is an example of the default CSRF Same-Origins rule:

 

app("CSRF Same-Origins"):
  requires(version: ARMR/2.8)
  http("Deny HTTP requests with invalid origin header (for all HTTP endpoints)"):
      csrf(same-origin)
      request()
    protect(message: "HTTP origin validation failed", severity: 7)
  endhttp
endapp
 


If protection is needed for specific HTTP endpoints, the specific relative URIs of the HTTP endpoints must be supplied in the​ request declaration of the CSRF ARMR rule.

For example:

 

app("CSRF Same-Origins"):
  requires(version: ARMR/2.8)
  http("Deny HTTP requests with invalid origin header (for specific HTTP endpoints)"):
    csrf(same-origin)
    request(paths: ["/path/to/vulnerablePage.jsp", "/path/to/vulnerableServlet"])
    protect(message: "HTTP origin validation failed", severity: 7)
  endhttp
endapp

Protective Action

When the CSRF STP rule is enabled in protect mode and a CSRF attack is identified then the malicious HTTP request is terminated and an HTTP 403 response is returned to the client.

When the CSRF Same-Origins rule is enabled in protect mode and a CSRF attack is identified then the malicious HTTP request is not terminated but all its HTTP parameters and cookies are considered malicious and are therefore stripped from the request, rendering it safe.

Rule Applicability

The CSRF Synchronizer Token Pattern (STP) rule

The CSRF STP rule is applicable and can be safely enabled in the following cases:

  • In traditional web applications where the HTTP response of the application is an HTML page.

  • In web applications that use the Servlet API to handle HTTP requests, responses and session management.

  • In web applications that require CSRF protection for pages and resources accessible via GET and POST HTTP methods only. For instance​ <form> tags that trigger PUT requests are not supported.

  • Where the srcdoc attribute present in​ <iframe>​ HTML elements is not protected against CSRF attacks.

Note that CSRF attacks are only meaningful when there is an HTTP session associated with the HTTP requests. Therefore, stateless applications, such as some RESTful APIs and unauthenticated HTTP requests that contain no valid HTTP session ID will not be protected via the CSRF STP rule.

By default, only POST HTTP requests are validated by the CSRF STP rule, if no method is configured in the rule. Users have the option to configure the CSRF STP rule to also enable protection for GET HTTP requests.

Users should not enable the CSRF STP rule if the web application:

  • Does not produce HTML responses via the Servlet API. Examples of such applications are RESTful API and XML-based Web Services.

  • Does not use the standard J2EE Servlet APIs:

    1. javax.servlet.http.HttpServletRequest

    2. javax.servlet.http.HttpServletResponse

    3. javax.servlet.http.HttpSession

Enabling the CSRF STP rule in these cases could cause Waratek to either provide no protection or break the normal application functionality.

The CSRF Same-Origins rule

The CSRF Same-Origins rule depends on the presence of the Origin or Referer headers in the HTTP requests. Although these headers are included in the HTTP requests the majority of the time, there are few use cases where they are not included. The following lists the main use cases:

  • Older browsers do not support the Origin header.

  • Internet Explorer 11 does not add the Origin header on a ​CORS​ request across sites of a trusted zone.

  • HTTP requests that occur after 302 redirect cross-origin requests do not include the Origin header.

  • Load balancers, proxies and embedded network devices are well known to strip or change the Referer or the Origin headers.

  • Browsers typically do not include the Origin header in bookmarked links.

In case of applications where the source origin does not match the target origin even in non-malicious requests, the hosts rule parameter can be used to whitelist known safe origins.

For example:

app("CSRF Same-Origins"):
  requires(version: ARMR/2.8)
  http("Deny HTTP requests with invalid origin header (with whitelisted hosts)"):
    csrf(same-origin, options: {hosts: ["account.example.org", "login.example.com"]})
    request()
    protect(message: "HTTP origin validation failed", severity: 7)
  endhttp
endapp

Only POST HTTP requests are validated by the CSRF Same-Origins ARMR rule.

Best Practices

Waratek recommends to also enable the XSS security rule in blocking mode to be protected against XSS attacks. If the application is vulnerable to XSS attacks then stealing the CSRF tokens would be possible via XSS attacks. This would allow attackers to bypass the CSRF protection.

Because of the fact that the CSRF STP rule might require some configuration, users are advised to first enable the CSRF Same-Origins rule as the first layer of defense against CSRF. Then, consider enabling the CSRF STP rule only in relevant applications first in monitoring / detect mode and later in blocking mode after the rule has been properly configured.

Given that the CSRF Same-Origins rule depends on the presence of the Origin HTTP header, it is recommended that the CSRF Same-Origins rule is enabled only after ensuring all users are on an up-to-date browser version.

It is also recommended that users enable the CSRF Same-Origins rule only for the vulnerable HTTP endpoints reported by their vulnerability scanners.

References

https://owasp.org/www-community/attacks/csrf

https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html

https://cwe.mitre.org/data/definitions/352.html