Search code examples
javatomcatcsrfcsrf-protectionnonce

Tomcat 8.5 anti-CSRF nonce not being generated


I have a web application that runs on Tomcat 8.5. I would like to update the application to rely on Tomcats native anti-CSRF tokens to protect key POST requests on the web app. I have done quite of bit of researched and followed a number of example yet I still cannot seem to get this to work.

web.xml:

<filter>
    <filter-name>CSRFPreventionFilter</filter-name>
    <filter-class> org.apache.catalina.filters.CsrfPreventionFilter </filter-class>
    <init-param>
        <param-name>entryPoints</param-name>
        <param-value>appNameRemoved/login.jsp</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CSRFPreventionFilter</filter-name>
    <url-pattern>/appNameRemoved/folder1/*</url-pattern>
</filter-mapping>

So at face value this appears to work. Any attempt to access a URL inside of folder1 is denied with a 403 (good). The issue arises when I try to generate the nonce value to allow authorized parties to access the privileaged area.

In my main.jsp (JSP opened after logging in on entry-point login.jsp), I have the following Java code to try to generate the nonce value:

String antiCSRF = response.encodeURL("/appNameRemoved/folder1/delete");

The issue is, the value generated is simply

"/appNameRemoved/folder1/delete" 

rather than an expected URL (as seen by other peoples examles) such as:

"/appNameRemoved/folder1/delete?org.apache.catalina.filters.CSRF_NONCE=CB5C65E1D87A39D5557D6BCBC24E54A9"

Hence my question, why is response.encodeURL() not actually encoding the URL with the nonce value even though as far as I can see, the filter is setup correctly and checking for nonce's when accessing the privileged URL's.

Thanks!


Solution

  • It seems you have kept your main.jsp (in which you are using response.encodeURL()) out side the folder /appNameRemoved/folder1/.

    By using

    <filter-mapping>
        <filter-name>CSRFPreventionFilter</filter-name>
        <url-pattern>/appNameRemoved/folder1/*</url-pattern>
    </filter-mapping>
    

    you are applying CSRFPreventionFilter to urls /appNameRemoved/folder1/*. i.e. all the urls with pattern /appNameRemoved/folder1/* will be protected with CSRF nonce.

    By applying

    <init-param>
       <param-name>entryPoints</param-name>
       <param-value>url1, url2</param-value>
    </init-param>
    

    you are saying tomcat that out of /appNameRemoved/folder1/*, url1 and url2 are allowed even without CSRF nonce.

    Now what you have done is

    1. You have put appNameRemoved/login.jsp as entry point which you do not need to do that because it is anyway accessible as it is outside /appNameRemoved/folder1/* urls.
    2. Perhaps your main.jsp in which you are using response.encodeURL("/appNameRemoved/folder1/delete"), is also out side /appNameRemoved/folder1/*. CSRF nounce will only be generated in the resources on which CSRFPreventionFilter is applied. Had your main.jsp been placed in folder /appNameRemoved/folder1/, proper CSRF nonce would have been added to the encoded url. Again in such case, to make main.jsp accessible, you would need to set it as entryPoint in your init prams

    Like this

    <init-param>
       <param-name>entryPoints</param-name>
       <param-value>appNameRemoved/folder1/main.jsp</param-value>
    </init-param>