The last Tomcat filter we are going to demonstrate is the Cross-Site Request Forgery Prevention filter, implemented in class org.apache.catalina.filters.CsrfPreventionFilter. Cross-site request forgery (commonly known as CSRF, pronounced ‘sea-surf’) is the hacking technique used to exploit vulnerabilities of web sites by issuing commands to a known web site as a user that the site trusts. The attacker uses the knowledge of the URL that performs some operation using a user’s session, and, if the session is still active, it can access the site and perform harmful operations without the user’s knowledge. A typical CSRF scenario is embedding known secure URL to HTML image tag, for example <img src=”http://www.mybank/com/myaccount/sendmoney.html?toaccount=122121″>. If the unsuspecting user loads a malicious web page with this URL, and at the same time user has the active session to the www.mybank.com web site, this image tag will be able to transfer money from the user’s account without their knowledge.
Tomcat’s CSRF filter prevents such attacks by generating a random nonce (random number issued once), which is used to encode the request URL, and is stored in the session as well. On every request, the nonce from the request is compared with the session, and if they don’t match, the request will not proceed. This means that a request from the malicious web site will not be able to perform the operation, as it won’t have the nonce associated with the current session.
CsrfPreventionFilter Configuration in the web.xml File
<filter> <filter-name>CSRFPreventionFilter</filter-name> <filter-class> org.apache.catalina.filters.CsrfPreventionFilter </filter-class> <init-param> <param-name>entryPoints</param-name> <param-value>/secure/index.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>CSRFPreventionFilter</filter-name> <url-pattern>/secure/*</url-pattern> </filter-mapping>
The filter class must reference the full class name of the CsrfPreventionFilter. The entryPoints is the only required initialization parameter for the Tomcat’s CSFR filter. It specifies the URLs that are mapped to the filter, but that do not require a nonce to be present in the request. These URLs are entry points to the protected part of the web application, and are used to generate nonces for the users who are accessing the application for the first time, and don’t have a nonce in the request. There must be at least one entry point present, otherwise the generated nonce would not be sent to the client. The value for entryPoints parameter is the comma separated list of the URLs . Since access to URLs configured here will be free (entry points URLs won’t be protected by CSFR filter), it is important that those URLs do not perform any security critical operation. In addition, only GET access to entryPoints URLs is allowed (POST will be forbidden).
Finally, we set the filter mapping. It is important that the entryPoints configured are matching the filter mapping – otherwise the nonce value will not be generated as required. Let’s see what this filter does when user tries to access protected URL. A user first must access one of the entryPoints URLs; you can consider these as site home pages. A user will be allowed access, but the CSRF filter will intercept the response and generate a random String (nonce) for it. This nonce will be cached and stored in the user session. At the same time, the response will encode the URL using the same nonce value. If the user wants to access any protected URL (that is not configured as an entry point), the same nonce value will be required to be present as a request parameter. If the parameter is not present, error page for status code 403 Forbidden will be displayed in the browser.
The URL with the nonce as the required parameter will need to be calculated programmatically before it’s rendered as part of HTML on the page. Let’s see an example of this based on the configuration from above listing. The URL /secure/showAccount.jsp is protected by a CSFR filter, and is not an entry point. Let’s assume that /secure/showAccount.jsp displays account information and must be protected from CSRF attack. User must access entry point URL (/secure/index.jsp) before going to show account page. If malicious web site tries to access account page directly (via HTML image tag for example), nonce will not be present in the request, and access will be forbidden.
But what if the user types the shown account URL directly in the browser (/secure/showAccount.jsp)? The user will still see the forbidden access page! This is because user does not know the nonce value that has been generated, and that must be passed as request parameter. If you are using the CSRF Prevention filter, all pages must be accessed by clicking the links from connected pages, starting from entry point page – you cannot just type the URL in the browser, as you won’t have the required nonce to pass back to the server!
Below shows the /secure/index.jsp page, and how it links to the protected /secure/showAccount.jsp page.
Encoding a URL with Nonce Parameter from JSP page
<% String url = response.encodeURL("apress/secure/showAccount.jsp"); %> <a href="<%=url%>">Show Account</a>
We generate the URL with nonce request parameter, by calling response.encodeURL(…) on the response object in the JSP (#1). As we said before, nonce is generated when entry point is accessed the first time. In addition, the URL encoded with the returned response will have same nonce added as request parameter. We use the encoded URL as link in the anchor HTML tag .If you take a look at the HTML source code of the generated page in the browser, you will see that the Show Account link points to the following URL:
The Show Account URL has been encoded by adding nonce parameter. The nonce parameter name is a constant defined in CsrfPreventionFilter – org.apache.catalina.filters.CSRF_NONCE. Its long String value is the actual random generated nonce. The protected Show Account page will only be rendered if the nonce value passed as parameter matches the one stored in the session cache. If the nonce value is missing, or does not match the session – 403 Forbidden page will be rendered instead. In addition to the required entryPoints, CsrfPreventionFilter has two more configurable initialization parameters, randomClass and nonceCacheSize.
Additional Initialization Parameters for CSRF Filter Configuration
randomClass Fully qualified name of the class that generate nonce values. Class specified must be an instance of java.util.Random. java.util.Random is the default class, if this parameter is not specified.
nonceCacheSize Number of nonce values to be cached for parallel requests, or when back and refresh buttons are used, which may result in nonce being generated twice. The default value is 5.