Adding HTTP Strict Transport Security(HSTS) in java with Tomcat 8

1. Overview:

Enabling HTTP Strict Transport Security (HSTS) for Tomcat 8:
HSTS is abbreviated as HTTP Strict Transport Security. HTTP Strict Transport Security (HTTP ) is a web security policy mechanism that helps to protect websites against protocol downgrade attacks and cookie hijacking.

Most of the companies do the Security vulnerability scan for your application and may be saying missing HTTP Strict Transport Security is missing as part of response. Please add HTTP header in response.

Adding HTTP Strict Transport Security(HSTS) in java, Tomcat


This can be done in two ways.

1) Tomcat 8 built in filter
2) Implementing Custom Filter

2.  Tomcat 8 built in filter

Before doing this, You must enable HTTPS redirect protocol in server. This post designed for tomcat server.
When we receive the HTTP request then internally need to redirect to HTTPS. below is the configuration for this.

2.1 tomcat8/conf/server.xml


<Connector executor="tomcatThreadPool"
           port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />
 

2.2 Tomcat server configuration:

If your application is deployed in tomcat 8 server, then there is a built in filter that will fulfill all your needs. HttpHeaderSecurityFilter class is provided by tomcat server. We must have tomcat version 8 to enable this feature.

Built in filter: org.apache.catalina.filters.HttpHeaderSecurityFilter

HSTS_HEADER_NAME = "Strict-Transport-Security"; is a predefined value and can not be changed by the developer. This constant is part of the HttpHeaderSecurityFilter.

Below are the parameters which can be configured in web.xml file.

  private boolean hstsEnabled;
  private int hstsMaxAgeSeconds;
  private boolean hstsIncludeSubDomains;
  private boolean hstsPreload;
  private String hstsHeaderValue;

Add the following configuration in tomcat8/conf/web.xml file which is loaded during server startup.

 <filter>
        <filter-name>httpHeaderSecurity</filter-name>
        <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
        <async-supported>true</async-supported>
<init-param>
<param-name>hstsMaxAgeSeconds</param-name>
<param-value>31536000</param-value>
</init-param>
<init-param>
<param-name>hstsIncludeSubDomains</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>hstsPreload</param-name>
<param-value>true</param-value>
</init-param>
    </filter>


<filter-mapping>
        <filter-name>httpHeaderSecurity</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

After adding, we should be now able to see in response header.

Strict-Transport-Security: max-age=31536000; includeSubDomains

The main advantage of configuring at server level is this is applicable for the all the application that deployed in this server and no need to configure for each application.

Drawback is we must take a note that while upgrading the tomcat server, we must do this change otherwise way be open for attackers.

3. Implementing Custom Filter

We can write our own filter to add HSTS in the response for every request. In some cases 1st methodology will not work even if we are using tomcat 8+ version.

Our custom filter class must implements interface javax.servlet.Filter and provide implementations for init(), doFilter() , destroy() methods.
I have written custom filter named HSTSFilter class and should be configured in web.xml file.

3.1 Custom HSTS Filter

package com.java.w3shools;

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;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HSTSFilter implements Filter {
private static final String HEADER_NAME = "Strict-Transport-Security";
private static final String MAX_AGE_DIRECTIVE = "max-age=%s";
private static final String INCLUDE_SUB_DOMAINS_DIRECTIVE = "includeSubDomains";
private static final Logger logger = LoggerFactory.getLogger(HSTSFilter.class);

private int maxAgeSeconds = 0;
private boolean includeSubDomains = false;
private String directives;

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.debug("request.isSecure() :: " + request.isSecure());
System.out.println("request.isSecure() :: " + request.isSecure());

if (request.isSecure() && response instanceof HttpServletResponse) {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader(HEADER_NAME, this.directives);
}
chain.doFilter(request, response);
}

public void init(FilterConfig filterConfig) throws ServletException {
maxAgeSeconds = Integer.parseInt(filterConfig.getInitParameter("maxAgeSeconds"));
includeSubDomains = "true".equals(filterConfig.getInitParameter("includeSubDomains"));

if (this.maxAgeSeconds <= 0) {
throw new ServletException("Invalid maxAgeSeconds value :: " + maxAgeSeconds);
}

this.directives = String.format(MAX_AGE_DIRECTIVE, this.maxAgeSeconds);
if (this.includeSubDomains) {
this.directives += (" ; " + INCLUDE_SUB_DOMAINS_DIRECTIVE);
}
System.out.println("directives :: "+directives);
}

@Override
public void destroy() {
}
}

3.2 Web.xml:


 <filter>
<filter-name>HSTSFilter</filter-name>
<filter-class>com.java.w3shools.HSTSFilter</filter-class>
<init-param>
<param-name>maxAgeSeconds</param-name>
<param-value>31536000</param-value>
</init-param>

<init-param>
<param-name>includeSubDomains</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>HSTSFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
 

4. Testing

 How to test HSTS is enabled or not

Implementing of HSTS is one challenging task and testing is the main part.

How to test HSTS changes are applied to the web application?

There are mainly three ways.

curl -s -D-  www.domain-name.com | grep Strict

Result expected:

Eg. curl -s -D-  http://localhost:8080/HSTSFilterDemo/index.html | grep Strict

HSTS-Test-curl-command

4.2 Chrome extension Postman 


Postman is a free add on in chrome browser. Result would be as below.

HSTS-Test-chrome-postman


4.3 Using third party website


There are many websites that checks for HSTS is enables for a website. Here are some example websites.

https://tools.geekflare.com/tools/hsts-test
https://hstspreload.org/

5. Conclusion

 In this tutorial, We have seen what is HSTS and how to implement using tomcat built-in filter and custom hsts filter. In further article, discussed testing whether strict-transport-security is added as part of response or not.

Complete project source code showed in this article is available on GitHub.
 

0 Comments