Skip to main content
Version: 2.9

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:

  1. 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.

requestThis declaration determines the HTTP endpoints for which protection is enabled.
synchronized-tokensThis declaration is specified with no parameters. Protection is enabled for all HTTP endpoints.
same-originAn 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-strings

  • the wildcard character (*) is supported to cover multiple URIs. This can be specified as:

    • a prefix */target.jsp

    • a suffix /myApplication/*

    • both a prefix and a suffix */target*

  • if the wildcard character is one of the characters in the path itself, it has to be escaped using the backslash character \*If 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)

csrfThis 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 following options 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 and POST)

    • 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 or unique)

    • 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 or no-validate)

    • if this option is not specified the default value is validate | | | same-origin | With this protection enabled, the following options 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*- 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 colonThis option can be used to whitelist both high level domains, or specific hostnames. For example, specifying mydomain.com will allow requests from various hosts within this domain, such as server1.mydomain.com and server2.mydomain.com. |

Then (Action)

synchronized-tokenssame-origin
protectCSRF 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.
detectMonitoring 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.A log message must be specified with this action.

As part of the action statement, the user may optionally specify the parameter stacktrace: “full”. When this parameter is specified, the stacktrace of the location of the attempted exploit is included in the security log entry.

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.7)
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.7)
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 2021-03-29T11:53:05.341+01:00 userX_system java 15891 - - CEF:0|ARMR:ARMR|ARMR|2.7|CSRF STP|Execute Rule|Very-High|rt=Mar 29 2021 11:53:05.341 +0100 dvchost=userX_system procid=15891 appVersion=1 ruleType=http securityFeature=http csrf stp act=protect msg=CSRF STP validation failed httpRequestUri=/spiracle/CSRFServlet httpRequestMethod=GET internalHttpRequestUri=/spiracle/CSRFServlet httpSessionId=E654F722AAFA3BF44F0D0BD4FB91134C httpCookies=JSESSIONID\=E654F722AAFA3BF44F0D0BD4FB91134C remoteIpAddress=0:0:0:0:0:0:0:1
<10>1 2021-03-29T10:03:16.832+01:00 userX_system java 2402 - - CEF:0|ARMR:ARMR|ARMR|2.7|CSRF Same Origin|Execute Rule|High|rt=Mar 29 2021 10:03:16.832 +0100 dvchost=userX_system procid=2402 appVersion=1 ruleType=http securityFeature=http csrf same origin act=protect msg=CSRF Same Origin validation failed reason=Missing source origin httpRequestUri=/spiracle/CSRFServlet httpRequestMethod=GET internalHttpRequestUri=/spiracle/CSRFServlet remoteIpAddress=127.0.0.1 httpSessionId=8944B619DD9B0ADBF37CA663F8337AFD httpCookies=JSESSIONID\=8944B619DD9B0ADBF37CA663F8337AFD

Further Examples

The following mods are the same as the previous examples, with the stacktrace also logged:

app("CSRF STP Mod - with stacktrace"):
requires(version: ARMR/2.7)
http("CSRF STP"):
request()
csrf(synchronized-tokens)
protect(message: "CSRF STP validation failed", severity: 9, stacktrace: "full")
endhttp
endapp
app("CSRF Same Origin Mod - with stacktrace"):
requires(version: ARMR/2.7)
http("CSRF Same Origin"):
request()
csrf(same-origin)
protect(message: "CSRF Same Origin validation failed", severity: High, stacktrace: "full")
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 2021-03-29T10:10:18.286+01:00 userX_system java 8189 - - CEF:0|ARMR:ARMR|ARMR|2.7|CSRF STP|Execute Rule|Very-High|rt=Mar 29 2021 10:10:18.286 +0100 dvchost=userX_system procid=8189 appVersion=1 ruleType=http securityFeature=http csrf stp act=protect msg=CSRF STP validation failed stacktrace=org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)\norg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)\norg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)\norg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)\norg.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)\norg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)\norg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)\norg.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)\norg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)\norg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)\norg.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)\norg.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)\norg.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)\njava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\njava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\norg.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\njava.lang.Thread.run(Thread.java:748) httpRequestUri=/spiracle/CSRFServlet httpRequestMethod=GET internalHttpRequestUri=/spiracle/CSRFServlet httpSessionId=5D7CE07F605C3A6ABCFDB35D065A95E5 httpCookies=JSESSIONID\=5D7CE07F605C3A6ABCFDB35D065A95E5 remoteIpAddress=0:0:0:0:0:0:0:1
<10>1 2021-03-30T10:05:09.120+01:00 userX_system java 2402 - - CEF:0|ARMR:ARMR|ARMR|2.7|CSRF Same Origin|Execute Rule|High|rt=Mar 30 2021 10:05:09.119 +0100 dvchost=userX_system procid=2402 appVersion=1 ruleType=http securityFeature=http csrf same origin act=protect msg=CSRF Same Origin validation failed stacktrace=org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)\norg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)\norg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)\norg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)\norg.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)\norg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)\norg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)\norg.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)\norg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)\norg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)\norg.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)\norg.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)\norg.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)\njava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\njava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\norg.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\njava.lang.Thread.run(Thread.java:748) reason=Missing source origin httpRequestUri=/spiracle/CSRFServlet httpRequestMethod=GET internalHttpRequestUri=/spiracle/CSRFServlet remoteIpAddress=127.0.0.1 httpSessionId=8944B619DD9B0ADBF37CA663F8337AFD httpCookies=JSESSIONID\=8944B619DD9B0ADBF37CA663F8337AFD

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.7)
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.7)
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.7)
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.7)
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

The following mod configures CSRF Same Origin protection for HTTP endpoints containing /vulnerable.

app("CSRF Same Origin Mod 3"):
requires(version: ARMR/2.7)
http("CSRF Same Origin"):
request(paths: ["*/vulnerable*"])
csrf(same-origin)
protect(message: "CSRF Same Origin validation failed", severity: High)
endhttp
endapp

The following mod configures CSRF Same Origin protection for all HTTP endpoints except for /myApplication/safe.jsp.

app("CSRF Same Origin Mod 4"):
requires(version: ARMR/2.7)
http("CSRF Same Origin"):
request()
csrf(same-origin, options:
{exclude: ["/myApplication/safe.jsp"]})
protect(message: "CSRF Same Origin validation failed", severity: Medium)
endhttp
endapp

The following mod configures CSRF Same Origin protection for all HTTP endpoints in /myApplication except for /myApplication/safe1.jsp and /myApplication/safe2.jsp.

app("CSRF Same Origin Mod 5"):
requires(version: ARMR/2.7)
http("CSRF Same Origin"):
request(paths: ["/myApplication/*"])
csrf(same-origin, options:
{exclude: ["/myApplication/safe1.jsp", "/myApplication/safe2.jsp"]})
protect(message: "CSRF Same Origin validation failed", severity: High)
endhttp
endapp

The following mod configures CSRF Same Origin protection for all HTTP endpoints, except for those ending with .jsp.

app("CSRF Same Origin Mod 6"):
requires(version: ARMR/2.7)
http("CSRF Same Origin"):
request()
csrf(same-origin, options:
{exclude: ["*.jsp"]})
protect(message: "CSRF Same Origin validation failed", severity: High)
endhttp
endapp