How to Secure Cache with Security Headers

Author: Maggie Wang


What is Caching?

Caching is a technique that stores a copy of data and reuses the saved data to serve future requests. By using a cache, an application's performance can be greatly improved.

Risks of Using a Cache

There are some risks associated with using a cache. First, users could get outdated information if data on server has been updated but response to user's requests are retrieved from old cache data. Second, caching sensitive data could pose serious security risks. If caching is enabled in client's browser, it's possible to access the sensitive data through the web browser’s cache even after the session has been closed. Hackers may attempt to utilize cache to obtain user credentials and other sensitive data or even render applications unusable.

Securing Cache Using Cache Headers

There are several methods to secure an application cache by using HTTP cache security headers. Cache-Control, Pragma, and Expires are the three major cache-related security headers:

Table of Cache-Control Directives:

Cache Directives/Instructions Description Allowed Values
Cacheability defines whether and where a response/request can be cached public, private, no-cache, no-store
Expiration defines the amount of time before the cache expires max-age=<seconds>, s-maxage=<seconds>, stale-while-revalidate=<seconds>, stale-if-error=<seconds>
Revalidation and reloading defines whether the cache needs to be revalidated must-revalidate, proxy-revalidate, immutable

For purposes of this article, we will focus on HTTP cache security headers implementation using Cache-Control for HTTP /1.1 clients and Pragma for HTTP/1.0 clients.

Technical Implementation

There are two ways of adding security headers: through infrastructure configuration or application code. Examples of infrastructure-level configuration include Apache configuration and Tomcat configuration. Examples of application code include implemented with Servlet Filter directly or Spring Security. There are advantages and disadvantages to both.

Pros & Cons of Infrastructure Configuration

Pros:

Cons:

Pros & Cons of Application Code Implementation

Pros:

Cons:

Examples of Infrastructure Configurations

Tomcat Configuration

Can only implement Cache-Control max-age directive by using ExpiresFilter controls filter [6]. Configuration example for web.xml:

        
            <filter>
                <filter-name>ExpiresFilter</filter-name>
                <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
                <init-param>
                    <param-name>ExpiresByType image</param-name>
                    <param-value>access plus 60 seconds</param-value>
                </init-param>
            </filter>
            <filter-mapping>
                <filter-name>ExpiresFilter</filter-name>
                <url-pattern>/*</url-pattern>
                <dispatcher>REQUEST</dispatcher>
            </filter-mapping>
        
        

Apache Configuration

Apache can be configured to set both Cache-Control and Pragma headers.[7] httpd.conf configuration example:

        
            httpd.conf
            # For HTTP/1.1 Request and Response
            Header set Cache-Control "max-age=0,no-cache, no-store"
            ## For HTTP/1.0, Request only
            Header set Pragma "no-cache"
        
        

Examples of Application Code Implementation (Spring Security OR Servlet Filter):

Using Spring Security: sets specific cache control header values by default. Default Cache related security headers are listed below.[8]

    • Cache-Control: no-cache, no-store, max-age=0, must-revalidate
    • Pragma: no-cache
    • Expires: 0

Using Servlet Filter: Create CacheControl Servlet Filter, then Add CacheControl Servlet Filter to servletContext.

Create CacheControl Servlet Filter, in our example, we use the same values as Spring Security default settings. For Cache-Control header, we use no-store, no-cache, must-revalidate, max-age=0; for Pragma, we use no-cache to support HTTP/1.0 clients.

           CacheControlFilter
        
            import java.io.IOException;

            import javax.servlet.Filter;
            import javax.servlet.FilterChain;
            import javax.servlet.FilterConfig;
            import javax.servlet.ServletException;
            import javax.servlet.ServletRequest;
            import javax.servlet.ServletResponse;
            import javax.servlet.http.HttpServletResponse;

            public class CacheControlHeaders implements Filter
            {

                @Override
                public void init(FilterConfig filterConfig) throws ServletException
                {
                    // Nothing to do in init method.
                }

                @Override
                public void destroy()
                {
                    // Nothing to do.
                }

                public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
                ServletException
                {
                    HttpServletResponse resp = (HttpServletResponse) response;
                    resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
                    resp.setHeader("Pragma", "no-cache");

                    chain.doFilter(request, response);
                }
            }
        
        

Add CacheControl Servlet Filter to servletContext, URL patterns can be modified per application requirements. For example, only applying cache-control headers to requests with sensitive information returned, or disabling cache-control header in static responses and only enable it for dynamically generated responses etc.

           CacheControlFilter
        
            protected void initCacheControlFilter(ServletContext servletContext)
            {
                // Add a cache control filter for HTTP request
                FilterRegistration.Dynamic httpSecurityHeadersFilter = servletContext.addFilter("cacheControlFilter",
                CacheControlFilter.class);
                httpSecurityHeadersFilter.addMappingForUrlPatterns(null, true, "*");
            }

        
        

Conclusion

Though caching helps in speeding up application performance, there are several drawbacks with using a cache, such as stale information and imposing security risks for sensitive information. Applying cache security headers is a simple and easy way to mitigate the risks of using a cache. To add the Cache-Control and Pragma security headers, implementations can be done using three different strategies: Apache configuration, Tomcat configuration, and application code. Apache can be configured for both Cache-Control and Pragma for applications using Apache server; Tomcat only supports partial Cache-Control directives; both Spring Security and Servlet Filter are application code implementations. Application teams should consider both the advantages and disadvantages of each implementation and their own application specific requirements when deciding which implementation to use.

References:

[1] HTTP Caching, (n.d.). MDN Web Docs, Retrieved Apr 13 2021, from https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching

[2] How Caching Sensitive Data Can Lead to the Downfall of Your Business, (n.d.). appknox, Retrieved Apr 13 2021, from https://www.appknox.com/blog/caching-sensitive-data

[3] Cache Control, (n.d.). MDN Web Docs, Retrieved Apr 13 2021, from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control

[4] HTTP headers | Pragma, (n.d.). GeeksforGeeks, Retrieved Apr 13 2021, from https://www.geeksforgeeks.org/http-headers-pragma/

[5] Class ExpiresFilter, (n.d.). Apache Tomcat, Retrieved Apr 13 2021, from https://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/filters/ExpiresFilter.html

[6] HTTP Cache Headers, (n.d.). keycdn, Retrieved Apr 13 2021, from https://www.keycdn.com/blog/http-cache-headers

[7] Caching, (n.d.). Httpd Apache, Retrieved Apr 13 2021, from https://httpd.apache.org/docs/2.4/en/caching.html

[8] Security Headers, (n.d.). Spring IO Docs, Retrieved Apr 13 2021, from https://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/headers.html