CSRF protection
In a Cross Site Request Forgery (CSRF) attack, a user unknowingly executes a malicious request on a website where they’re authenticated. A CSRF attack usually includes a link or script in a web page. When a user accesses the link or script, the page executes an HTTP request on the site where the user is authenticated.
CSRF attacks interact with HTTP requests as follows:
-
CSRF attacks can execute POST, PUT, and DELETE requests on the targeted server. For example, a CSRF attack can transfer funds out of a bank account or change a user’s password.
-
Because of same-origin policy, CSRF attacks cannot access any response from the targeted server.
When IG processes POST, PUT, and DELETE requests, it checks a custom HTTP header in the request. If a CSRF token isn’t present in the header or not valid, IG rejects the request and returns a valid CSRF token in the response.
Rogue websites that attempt CSRF attacks operate in a different website domain to the targeted website. Because of same-origin policy, rogue websites can’t access a response from the targeted website, and can’t, therefore, access the response or CSRF token.
The following example shows the data flow when an authenticated user sends a POST request to an application protected against CSRF:
The following example shows the data flow when an authenticated user sends a POST request from a rogue site to an application protected against CSRF:
-
Set up SSO, so that AM authenticates users to the sample app through IG:
-
Set up AM and IG as described in Authenticate with SSO through the default authentication service.
-
Remove the condition in
sso.json
, so that the route matches all requests:"condition": "${find(request.uri.path, '^/home/sso')}"
-
-
Test the setup without CSRF protection:
-
Go to https://ig.example.com:8443/bank/index, and log in to the Sample App Bank through AM, as user
demo
, passwordCh4ng31t
. -
Send a bank transfer of $10 to Bob, and note that the transfer is successful.
-
Go to http://localhost:8081/bank/attack-autosubmit to simulate a CSRF attack.
In deployments that use a different protocol, hostname, or port for IG, append the
igUrl
parameter, as follows:http://localhost:8081/bank/attack-autosubmit?igUrl=protocol://hostname:port
When you access this page, a hidden HTML form is automatically submitted to transfer $1000 to the rogue user, using the IG session cookie to authenticate to the bank.
In the bank transaction history, note that $1000 is debited.
-
-
Test the setup with CSRF protection:
-
In IG, replace
sso.json
with the following route:{ "name": "Csrf", "baseURI": "http://app.example.com:8081", "heap": [ { "name": "SystemAndEnvSecretStore-1", "type": "SystemAndEnvSecretStore" }, { "name": "AmService-1", "type": "AmService", "config": { "agent": { "username": "ig_agent", "passwordSecretId": "agent.secret.id" }, "secretsProvider": "SystemAndEnvSecretStore-1", "url": "http://am.example.com:8088/openam/" } }, { "name": "FailureHandler-1", "type": "StaticResponseHandler", "config": { "status": 403, "headers": { "Content-Type": [ "text/plain; charset=UTF-8" ] }, "entity": "Request forbidden" } } ], "handler": { "type": "Chain", "config": { "filters": [ { "name": "SingleSignOnFilter-1", "type": "SingleSignOnFilter", "config": { "amService": "AmService-1" } }, { "name": "CsrfFilter-1", "type": "CsrfFilter", "config": { "cookieName": "iPlanetDirectoryPro", "failureHandler": "FailureHandler-1" } } ], "handler": "ReverseProxyHandler" } } }
Notice the following features of the route compared to
sso.json
:-
The CsrfFilter checks the AM session cookie for the
X-CSRF-Token
header. If a CSRF token isn’t present in the header or not valid, the filter rejects the request and provides a valid CSRF token in the header.
-
-
Go to https://ig.example.com:8443/bank/index, and send a bank transfer of $10 to Alice.
Because there is no CSRF token, IG responds with an HTTP 403, and provides the token.
-
Send the transfer again, and note that because the CSRF token is provided the transfer is successful.
-
Go to http://localhost:8081/bank/attack-autosubmit to automatically send a rogue transfer.
In deployments that use a different protocol, hostname, or port for IG, append the
igUrl
parameter, as follows:http://localhost:8081/bank/attack-autosubmit?igUrl=protocol://hostname:port
Because there is no CSRF token, IG rejects the request and provides the CSRF token. However, because the rogue site is in a different domain to
ig.example.com
it can’t access the CSRF token.
-