CSRF Security Feature
Overview
Cross-Site Request Forgery (CSRF/XSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated. CSRF attacks specifically target state-changing requests. They are not aimed at data theft since the attacker has no way to see the response to the forged request.
Cross-Site Request Forgery vulnerabilities are covered by CWE-352.
Waratek provides protection against CSRF attacks via two separate techniques:
- The Synchronizer Token Pattern (STP)
With this security feature enabled the agent will inject CSRF tokens into 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.
Only cases that trigger GET and POST requests are supported. For instance, <form> tags that trigger PUT requests are not supported.
The srcdoc attribute present in <iframe> HTML elements are not protected against CSRF attacks.
The Synchronizer Token Pattern uses HTTP sessions to store the trusted CSRF token. Any web application that does not use the javax.servlet.http.HttpSession
interface for session management is not supported and will thus not be protected from CSRF attacks.
Additionally, unauthenticated HTTP requests that do not contain a valid HTTP session ID will not be validated.
HTTP requests built dynamically using JavaScript or submitted using AJAX techniques are not supported and the CSRF protection will refuse to serve them. This may disrupt the usual work-flow of the application. Users can avoid this by using the whitelist functionality of this rule, as described below.
Additionally, ajax: no-validate
option can be used to disable validation of such requests. See below for more details.
2. Verifying the Same Origin with Standard Headers
With this security feature enabled the agent checks if the source origin of the received HTTP request is 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 HTTP ARMR rule.
Only cases that trigger POST requests are supported. For example, same origin validation will not be triggered for GET or PUT HTTP requests.
If none of the origin headers are present, the origin validation cannot be performed and the rule blocks the HTTP request.
Users can enable each of these two protection types individually, or both simultaneously as recommended by OWASP.
Given (Condition)
The CSRF security feature is enabled using the ARMR http
rule. With this rule the user specifies the condition request
.
request | This declaration determines the HTTP endpoints for which protection is enabled. | |
synchronized-tokens | This declaration is specified with no parameters. Protection is enabled for all HTTP endpoints. | |
same-origin | An optional key value pair can be supplied to this declaration where the key is paths and the value can be one of the following (indicating specifically targeted HTTP endpoints) :-- a quoted string |
-
a list of one or more quoted-stringsIf no value is specified then protection will be applied to all HTTP endpoints by default.If a string value is specified then it must:- not be empty
-
be a valid relative URI |
When (Event)
csrf | This declaration switches on the CSRF security feature and must be declared with one of the following values:- synchronized-tokens enabling CSRF protection via STP |
-
same-origin
enabling CSRF protection via validation of origin headers | | | | synchronized-tokens | With this protection enabled, the followingoptions
may also be specified: -exclude
-
disable protection for any specific URIs
-
if this option is not specified the default value is an empty exclusion list, therefore enabling protection for all web-pages
-
specific URIs can be specified as a single string literal, or a non-empty array of one or more string literals
-
the wildcard character (*) is supported to cover multiple URIs. This can be specified as:
-
a prefix
*/safe.jsp
-
a suffix
/myApplication/*
-
both a prefix and a suffix
*/safe*
-
-
-
method
-
specify the particular HTTP method(s) for which to enable protection (currently supported values are
GET
andPOST
) -
if this option is not specified - the default value is
POST
-
-
token-type
-
specify if a different token should be generated for each HTTP method type, or if a shared value is to be used for all HTTP method types (supported values are
shared
orunique
) -
if this option is not specified the default value is
shared
-
-
token-name
-
specify the name of the token to be injected into the HTML
-
token names must be between 5 - 20 characters long, and each character of the token name must be URL safe
-
if this option is not specified the default value is
_X-CSRF-TOKEN
-
-
ajax
-
specify whether the agent should validate AJAX requests (supported values are
validate
orno-validate
) -
if this option is not specified the default value is
validate
| | | same-origin | With this protection enabled, the followingoptions
may also be specified: -hosts
-
should the source origin not match the target origin, even for a non-malicious request, this option can be used to whitelist known safe origins
-
can specify a single string literal, or a non-empty array of one or more string literals
-
each string should comprise a host name and optional port number, separated by a colon |
-
Then (Action)
synchronized-tokens | same-origin | |
protect | CSRF attacks are blocked by the agent. The malicious HTTP request is terminated and an HTTP 403 response is returned to the client. If configured, a log message is generated with details of the event. | If a CSRF attack is identified then the malicious HTTP request is not terminated, but all of its HTTP parameters and cookies are considered malicious and are stripped from the request, rendering it safe. |
detect | Monitoring mode: the application behaves as normal. Malicious HTTP requests that are the result of a CSRF attack are allowed to be processed by the application. If configured, a log message is generated with details of the event. | Monitoring mode: the application behaves as normal. If a CSRF attack is identified then the agent will allow the request, along with all of its HTTP parameters and cookies, to be processed by the application. If configured, a log message is generated with details of the event. |
Examples
The following example shows how the user may configure the CSRF STP security feature to enable protection for all HTTP endpoints, and using the default value for all optional parameters to the csrf
declaration:
app("CSRF STP Mod"):
requires(version: ARMR/2.2)
http("CSRF STP"):
request()
csrf(synchronized-tokens)
protect(message: "CSRF STP validation failed", severity: 9)
endhttp
endapp
Similarly, the following example shows how the user may configure the CSRF Same Origins security feature to enable protection for HTTP endpoints. In this example, the user has not specified any known safe origins.
app("CSRF Same Origin Mod"):
requires(version: ARMR/2.2)
http("CSRF Same Origin"):
request()
csrf(same-origin)
protect(message: "CSRF Same Origin validation failed", severity: High)
endhttp
endapp
Logging
A log entry similar to the following is generated when each of the above http
rules identify a CSRF attack, respectively:
<9>1 2020-07-03T11:38:08.213+01:00 l-qa02 java 12601 - - CEF:0|ARMR:CSRF STP Mod|CSRF STP Mod|2.2|CSRF STP|Execute Rule|Very-High|rt=Jul 03 2020 11:38:08.211 +0100 dvchost=l-qa02 procid=12601 outcome=success act=protect msg=CSRF STP validation failed metadata="HeaderInfo":{"remoteAddr":"0:0:0:0:0:0:0:1","requestURI":"/spiracle/CSRFServlet","sessionId":"5EF9464DEFFD188A4C66472051CFF2CF","cookieNames":{"JSESSIONID":"5EF9464DEFFD188A4C66472051CFF2CF","CUSTOMER_UUID":"05b7b9d7-2046-4014-b8c9-bc53c79790c5"}}
<10>1 2020-07-03T11:41:10.718+01:00 l-qa02 java 12601 - - CEF:0|ARMR:CSRF Same Origin Mod|CSRF Same Origin Mod|2.2|CSRF Same Origin|Execute Rule|High|rt=Jul 03 2020 11:41:10.716 +0100 dvchost=l-qa02 procid=12601 outcome=success act=protect msg=CSRF Same Origin validation failed reason=Missing source origin uri-path=/spiracle/CSRFServlet remote-address=127.0.0.1 session-id=5EF9464DEFFD188A4C66472051CFF2CF cookies="JSESSIONID":"5EF9464DEFFD188A4C66472051CFF2CF","CUSTOMER_UUID":"05b7b9d7-2046-4014-b8c9-bc53c79790c5"
Further Examples
The following mod configures CSRF STP protection for all HTTP endpoints. Protection is enabled for both GET and POST requests, with a different token used for each request type.
app("CSRF STP Mod 2"):
requires(version: ARMR/2.2)
http("CSRF STP"):
request()
csrf(synchronized-tokens, options:
{method: [POST, GET],
token-type: unique})
protect(message: "CSRF STP validation failed", severity: 10)
endhttp
endapp
The following mod detects CSRF attacks that fail CSRF STP validation. Validation is applied to all HTTP endpoints, except for /myApplication/safe.jsp
. This applies to GET requests only.
app("CSRF STP Mod 3"):
requires(version: ARMR/2.2)
http("CSRF STP"):
request()
csrf(synchronized-tokens, options:
{exclude: ["/myApplication/safe.jsp"],
method: [GET]})
detect(message: "CSRF STP validation failed", severity: 5)
endhttp
endapp
The following mod detects CSRF attacks that fail CSRF STP validation. Validation is applied to all HTTP endpoints, except for those ending with .jsp
. This applies to both GET and POST requests.
app("CSRF STP Mod 4"):
requires(version: ARMR/2.2)
http("CSRF STP"):
request()
csrf(synchronized-tokens, options:
{exclude: ["*.jsp"],
method: [GET, POST]})
detect(message: "CSRF STP validation failed", severity: Very-High)
endhttp
endapp
The following mod configures CSRF Same Origin protection for specific HTTP endpoints. The hosts host
and host2:8080
are whitelisted such that protection is not applied to these hosts even if the source origin and target origin does not match.
app("CSRF Same Origin Mod 2"):
requires(version: ARMR/2.2)
http("CSRF Same Origin"):
request(paths: ["/path/to/vulnerablePage.jsp",
"/path/to/vulnerableServlet"])
csrf(same-origin, options:
{hosts: ["host1", "host2:8080"]})
protect(message: "CSRF Same Origin validation failed", severity: Medium)
endhttp
endapp