« All Software Development Articles

CORS and the Tomcat Built-in CorsFilter

3/13/2020

Introduction

Cross-Origin Resource Sharing refers to the technique used by web browsers to allow multiple servers to supply the contents of a single page. This article will discuss the restrictions that web browsers put on a page loading resources from multiple servers. Then it will demonstrate how to configure a Java web application running on a Tomcat server to correctly serve CORS requests.

What is CORS?

CORS policy in the browser is triggered when a page loaded in the browser requests resources from a different domain. These requests are usually for API responses, but can also be for JavaScript code, fonts, images, and other types of resources.

For example, when someone browses to mario.com and a page is loaded, a button click might call some JavaScript that uses Ajax or the more modern Fetch to make a POST request to luigi.com. If this call happens to send cookies or certain headers then the browser will stop and consider whether it should be loading the information from luigi.com.

  Some requests fall under the category of "simple requests" and will not trigger CORS policy. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS describes in detail which requests will cause browsers to enable CORS behavior and all of the CORS related headers browsers and servers can use.

But why? Consider different domains. Instead of mario.com and luigi.com, what if the site loaded in the browser was badly-written-forum.com where a bad guy decided to post some malicious JavaScript. That script tries to cause the visitor's browser to make a request to visitors-bank.com and send response information off to the attacker. The goal of CORS policy is for the user's browser to intervene and not allow scripts on badly-written-forum.com to access information from visitors-bank.com.

Sharing Across Origins

CORS features in browsers also allow visitors-bank.com to decide that they trust certain domains, such as trusted-banking-tool.com, and let browsers know that those trusted domains are free to share their responses with scripts from those sites.

When a browser determines that CORS restrictions are enabled it will check the non-originating domain and send it a request to see if it trusts the originating domain. In our example, the user opens trusted-banking-tool.com in the browser then clicks a button to sync account info from visitors-bank.com.

Due to CORS policy the browser will first send a "pre-flight" OPTIONS request with a few CORS related request headers. In order for the true request (GET, POST, etc.) to succeed the browser expects the response from the "pre-flight" OPTIONS request to contain at least two CORS related response headers. The required repsonse headers that visitors-bank.com sends in response to the "pre-flight" OPTIONS request are:


Access-Control-Allow-Origin: trusted-banking-tool.com
Access-Control-Allow-Methods: POST, GET, OPTIONS

The browser is notified that data from visitors-bank.com is allowed to be used when the user is viewing pages on trusted-banking-tool.com. The browser will then send the true request and load data from visitors-bank.com successfully.

  To send the Authorization header, commonly used for Bearer tokens and NTLM/Windows authentication, the "credentials" parameter to the Fetch init options must be set to "include".

Using the Built-in Tomcat CorsFilter

The Tomcat application server has a built-in filter to respond properly to the "pre-flight" OPTIONS request for trusted originating domains. It is configured in the application's web.xml.

  The param-value for the cors.allowed.origins param is a comma separated list of trusted originating domains. For full documentation on this filter's settings visit https://tomcat.apache.org/tomcat-9.0-doc/config/filter.html#CORS_Filter.

A sample web.xml application descriptor filter definition that the example visitors-bank.com site might use is below. In a production environment pay special attention to the url-pattern used for this filter.


<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>https://trusted-banking-tool.com</param-value>
    </init-param>
    <init-param>
        <param-name>cors.support.credentials</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Done

If you have any feedback or corrections please let me know on my contact page.

Have a nice day.