Skip to main content
Version: 3.14.x.x LTS

CSRFFilter

The filter offers protection from Cross Site Request Forgery and related attacks by imposing additional conditions on incoming requests to filter out those not originating from the legitimate end user. The following tests are available, listed in the order of execution:

Referer Header

If an incoming HTTP request contains the 'Referer' header, the hostname must match the 'Host' header.

Request ID

JavaScript code with a random session-bound ID is injected into all HTML responses sent to the client. As the page loads in the browser, the script includes the ID in all the references pointing back to the web application. Depending on the request type, the ID is added either as an HTTP header, query parameter or a hidden field in forms. The filter checks incoming requests for the presence of the correct ID and removes it from all the requests passed through. The test should be enabled selectively for the most sensitive requests only, the injected script is not guaranteed to rewrite all the links.

Milestones

Certain URIs can be defined to constitute a milestone. If milestone requests are made, they must arrive in a fixed preconfigured order.

Classname
ch::nevis::isiweb4::filter::validation::CSRFFilter

Library
libInputValidationFilter.so.1

Configuration

NameTypeUsage ConstraintsDefaultDescription
RefererHeaderCheckenum: required, true, falseconditionaltrueThis parameter defines whether the Referer HTTP header check is enabled, disabled or required:
false: Referer header check is disabled.;
true: Referer header check is enabled if the header is present.;
required: Blocks the request if the referer header is not present, else validates it.
InjectedIdCheckbooleanrequireddefault: false, secure default: trueEnables injection of JavaScript in HTML responses as well as the corresponding check on requests.
IdCheckEnablebooleanrequired, conditional; Supported pragmas: breakdefault: trueWith this parameter you can turn on/off the check for the injected Id.
InjectionScriptPathstringrequireddefault: /var/opt/nevisproxy/ <instance>/conf/csrf-inject.jsDefines the location of the .js file injected to HTML responses. The provided script (csrf-inject.js) works only on outgoing AJAX calls and URLs in the <href> tag. Some use cases:
1. For more complex functions, such as javascript.window.open(), copy the csrf-inject.js script and adapt it to your backend(s).
2. To support some basic JavaScript functions, use a copy of the file csrf-with-basic-javascript-support-csrf-inject.js. You find this file in the examples directory of your installed nevisProxy package.
3. To support Captcha (or other pages containing image links), use a copy of the file csrf-with-image-support-csrf-inject.js. Also this file is located in theexamples directory of your installed nevisProxy package.
IdQueryParamNamestringrequired, advancedcsrfpIdName of the extra parameter with the ID added to requests by the injected JavaScript.
ProtectedURIslist of regexpsrequirednoneNewline separated list of regular expressions that define request URIs for which an ID is required. All other requests will be allowed. The default regex type is "PCRE(da)". The list should only contain selected sensitive URIs.
IdCheckWhitelistlist of regexpsoptionalnoneNewline separated list of regular expressions that define URIs exempt from ID checks, even if they match ProtectedURIs. The default regex type is "PCRE(da)".
ProtectPayloadOnlybooleanrequiredtrueOnly requires the ID of requests that carry non-trivial payload. All HTTP requests without parameters will be allowed.
ContentTypes.htmllist of content type regexpsoptional, advanced^text/html, ^application/xhtmlNewline separated list of regular expressions defining content types for HTML. If the content type of a response matches one of the configured values, the JavaScript code will be injected. The default regex type is "PCRE(da)".
RewriteBufferSizeintegeroptional, advanced16KThe size of the internal buffer (in bytes) for buffering HTML tags. Only relevant if the JavaScript is injected. (see InjectedIdCheck).
MilestoneCheckbooleanrequiredfalseSpecifies whether the milestone URLs check is enabled.
Milestoneslist of regexpsoptionalnoneNewline separated list of regular expressions that define milestone URIs. The milestone requests, if any, must be made precisely in the order listed. The default regex type is "PCRE(da)".
MilestoneRevisitbooleanoptional, advancedtrueIf enabled, repeated requests to milestone URIs are allowed, as long as all the earlier milestones have been requested at least once. When disabled, every milestone request can be made at most once during a session.
CSRFPolicylist of error policiesoptional, advancedREFERER_MISMATCH: block:403, MILESTONE_MISMATCH: block:403, ID_MISMATCH: block:403Defines actions to perform when a particular test fails.
format: <status>:<action>[:<error-code>][:<url>] where status is one of: REFERER_MISMATCH, MILESTONE_MISMATCH, ID_MISMATCH.
action: BLOCK, REDIRECT, PASSTHROUGH, TRACE
error code: HTTP Error code to return, 403 by default (only applies to BLOCK)
url: The destination URL for REDIRECT (colon characters within the url must be escaped)
RedirectPolicyenum: on, off, protectedUriOnlyoptionalonThis parameter controls the rewriting of redirect URIs. The default value is "on", which means that the system will overwrite every redirect URI. If you set the parameter to "protectedUriOnly", only the configured (and not whitelisted) URIs will be rewritten. To disable the feature, set the parameter to "off".
RegenerateIdbooleanoptionalfalseIf this parameter is set to "true", the system will generate a new ID for each request. If set to "false", which is the default, the existing ID remains in use.

This filter injects Javascript code to implement Cross Site Request Forgery.

Example
<filter>
<filter-name>CSRFInjectionFilter</filter-name>
<filter-class>ch::nevis::isiweb4::filter::validation::CSRFFilter</filter-class>
<init-param>
<param-name>InjectionScriptPath</param-name>
<param-value>/opt/nevisproxy/template/conf/csrf-inject.js</param-value>
</init-param>
<init-param>
<param-name>InjectedIdCheck</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>IdQueryParamName</param-name>
<param-value>csrfpId</param-value>
</init-param>
<init-param>
<param-name>ProtectedURIs</param-name>
<param-value>/foo/.*</param-value>
</init-param>
</filter>

If there are links pointing to non-protected URIs, you can modify the injected JavaScript to avoid these unprotected-URI links, and to rewrite only specific links. Below follows an example of how to do this.

  • First, replace the csrfCheckDomain function with the following one:

    function csrfCheckDomain(attribute) {
    var index;
    index = attribute.indexOf("//");
    if(index != 0 && index != 5 && index != 6) {
    return relativeCheck(attribute)
    }
    index = index + 2;
    try {
    var desthost = attribute.substring(index, location.hostname.length+index);
    var destpath = attribute.substring(location.hostname.length+index);
    }
    catch(e) {
    return false;
    }
    if (desthost == location.hostname) {
    return relativeCheck(destpath);
    }
    return false;
    }
  • Then add one of the next relativeCheck function implementations:

    • Rewrite links pointing to a specific path:

      function relativeCheck(path) {
      var protected = "/example/auth/emailchange";
      return (path.indexOf(protected) == 0)
      }
    • Rewrite links pointing to the same page:

      function relativeCheck(path) {
      return (path.indexOf(location.pathname) == 0)
      }