How to set the SameSite attribute in Java Web applications

This short article describes how you can set the SameSite property in HTTP Cookies for Web applications, with special focus on WildFly‘s Web server, which is Undertow.

What is SameSite ? SameSite is a property that you can set in HTTP cookies to avoid false cross-site request (CSRF) attacks in web applications:

  • When SameSite is set to “LAX“, the cookie is sent in requests within the same site and in Get requests from other sites. It is not sent in GET requests that are cross-domain.
  • When SameSite is set to “Strict” it ensures that the cookie is sent in requests only within the same site.
  • When SameSite is set to “None” you enable cookies for cross-site access.

SameSite in Java applications

The Servlet API does not contain a standard way to deal with SameSite. Therefore, there are no standard properties or code to configure it. There are however several ways to set the SameSite attribute in Undertow Web server if you are running WildFly 19 or newer.

Firstly, you can configure the SameSite attribute as Undertow filter in your configuration. For example:

/subsystem=undertow/configuration=filter/expression-filter=samesite-cookie-filter:add(expression=samesite-cookie(mode\=strict))
/subsystem=undertow/server=default-server/host=default-host/filter-ref=samesite-cookie-filter:add()

Then, if you try to inspect the Response Cookies for your Web application, you will see that it includes the samesite Attribute:

configure samesite attribute wildfly

On the other hand, if you want to set the samesite Attribute at application level, you can do it in the following way:

Create a file “src/main/webapp/WEB-INF/undertow-handlers.conf” in your Web application. Inside this file specify the samesite policy. For example:

samesite-cookie(mode=None)

This is an Handler predicate which applies the SameSite=None attribute to all cookies for requests of your Web application.

Not all clients support the SameSite=None attribute though. In order to skip the attribute check (when the client is not compatible) you can use:

samesite-cookie(mode=None, enable-client-checker=false)

Secure SameSite

Although the strategies to implement SameSite attribute is pretty simple, it can lead to insecure applications. If you send your cookies everywhere as default, you can be vulnerable to CSRF and unintentional information leakage. To provide users with a safer navigation experience, the IETF proposal (Incrementally Better Cookies lays out two key changes:

  • Cookies without a SameSite attribute will default to SameSite=Lax.
  • Cookies with SameSite=None must also specify Secure, meaning they require a secure context.

In terms of Handler configuration, the Secure attribute happens under the hoods unless you add “add-secure-for-none=false” parameter in the handler:

path(/webapp)->samesite-cookie(mode=None, enable-client-checker=false,add-secure-for-none=false)

Setting SameSite for older WildFly versions

If you are using a WildFly version older than 19, one simple solution is to add a session-cookie element with the SameSite policy in your Servlet Container configuration:

/subsystem=undertow/servlet-container=default/setting=session-cookie:add(comment="; SameSite=None")

This reflects in the following XML configuration:

<servlet-container name="default">
    <jsp-config/>
    <session-cookie comment="; SameSite=None"/>
    <websockets/>
</servlet-container>

Warning: Since Undertow quotes the comment values when using version 0 or version 1 cookies, you need to set the System Property io.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION to true at start up::

 ./bin/standalone.sh -Dio.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATIOM

Setting SameSite with a Servlet Filter

On the other hand, if you are not using WildFly as application server, the recommended approach, until this is supported in Jakarta Servlet specification, is to use a simple Servlet Filter to inject the SameSite attribute in the HTTP Response:

import java.io.IOException;
import java.util.Collection;

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 SameSiteFilter implements javax.servlet.Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        chain.doFilter(request, response);
        addSameSiteAttribute((HttpServletResponse) response); // add SameSite=strict cookie attribute
    }

    private void addSameSiteAttribute(HttpServletResponse response) {
        Collection<String> headers = response.getHeaders("Set-Cookie");
        boolean firstHeader = true;
        for (String header : headers) {  
            if (firstHeader) {
                response.setHeader("Set-Cookie", String.format("%s; %s", header, "SameSite=Strict"));
                firstHeader = false;
                continue;
            }
            response.addHeader("Set-Cookie", String.format("%s; %s", header, "SameSite=Strict"));
        }
    }

    @Override
    public void destroy() {

    }
}

Setting SameSite in the httpd front end

Finally, if your application server is fronted by an httpd server, you can also set the SameSite attribute using the Header directive.

For example, to set SameSite only on JSESSIONID cookie:

Header edit Set-Cookie ^(JSESSIONID.*)$ $1;HttpOnly;Secure;SameSite=None

To set SameSite on ALL cookies :

Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure;SameSite=None

Configuring the SameSite Attribute in Spring Boot applications

To configure this attribute in Spring Boot applications, you need the version 2.6 of Spring Boot. This article covers in detail the configuration steps: Configuring the Same Site Attribute in Spring Boot

Found the article helpful? if so please follow us on Socials