How to enable samesite for jsessionid cookie

无人久伴 提交于 2020-07-29 05:27:51

问题


How can i enable samesite for my web application which runs on wildfly as. Checked standalone.xml however could not find an appropriate tag within

<servlet-container name="default">
    <session-cookie http-only="true" secure="true"/>
    <jsp-config/>
</servlet-container>

回答1:


As for now the Java Servlet 4.0 specification doesn't support the SameSite cookie attribute. You can see available attributes by opening javax.servlet.http.Cookie java class.

However, there are a couple of workarounds. You can override Set-Cookie attribute manually.

The first approach (using Spring's AuthenticationSuccessHandler):

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        addSameSiteCookieAttribute(response);    // add SameSite=strict to Set-Cookie attribute
        response.sendRedirect("/hello"); // redirect to hello.html after success auth
    }

    private void addSameSiteCookieAttribute(HttpServletResponse response) {
        Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE);
        boolean firstHeader = true;
        for (String header : headers) { // there can be multiple Set-Cookie attributes
            if (firstHeader) {
                response.setHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=Strict"));
                firstHeader = false;
                continue;
            }
            response.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=Strict"));
        }
    }
}

The second approach (using javax.servlet.Filter):

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;

import org.springframework.http.HttpHeaders;

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);
        addSameSiteCookieAttribute((HttpServletResponse) response); // add SameSite=strict cookie attribute
    }

    private void addSameSiteCookieAttribute(HttpServletResponse response) {
        Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE);
        boolean firstHeader = true;
        for (String header : headers) { // there can be multiple Set-Cookie attributes
            if (firstHeader) {
                response.setHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=Strict"));
                firstHeader = false;
                continue;
            }
            response.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=Strict"));
        }
    }

    @Override
    public void destroy() {

    }
}

You can look at this demo project on the GitHub for more details on the configuration for org.springframework.security.web.authentication.AuthenticationSuccessHandler or javax.servlet.Filter.

The WebSecurityConfig contains all the necessary configuration.

Using addHeader is not guaranteed to work because basically the Servlet container manages the creation of the Session and Cookie. For example, both approaches won't work in case you return JSON in response body because application server will overwrite Set-Cookie header during flushing of response. However, above approaches will work in cases, when you redirect a user to another page after successful authentication.




回答2:


One workaround is to hack the SameSite setting into the cookie by using another attribute (e.g. comment):

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

But because Undertow quotes the comment (and other) values when using version 0 or version 1 cookies, JBoss/WildFly needs to be running with the io.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION system property set to true:

 ./bin/standalone.sh -Dio.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION=true

This will give you the desired result:

This approach is obviously hacky, and relies entirely on Undertow implementation details, so I'd recommend configuring on the web server or load balancer level instead.




回答3:


For Spring Boot with the currently latest release:

If you do not have the latest spring-boot-starter-tomcat check the SameSiteCookies enum for value UNSET, if the value is missing you need a newer release because it will skip the value SameSite=None.

@Component
public class SameSiteTomcatCookieProcessorCustomizationBean implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>
{
    @Override
    public void customize(TomcatServletWebServerFactory server) {

        server.getTomcatContextCustomizers().add(new TomcatContextCustomizer()
        {
            @Override
            public void customize(Context context)
            {
                Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
                cookieProcessor.setSameSiteCookies("None");
                context.setCookieProcessor(cookieProcessor);
            }
        });
    }
}



回答4:


My workaround, which works in JBoss EAP 7.2, is a custom handler. I use it as a global handler. But you can also use it in the jboss-web.xml. You need to play with the cookie implementation because undertow only allows Strict or Lax for samesite (it throws '"UT000162: Same-site attribute None is invalid. It must be Strict or Lax"' if you use cookie.setSameSiteMode("None"))

import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.Cookie;
import java.lang.reflect.Proxy;
import java.util.Map;

public class CookieSameSiteHandler implements HttpHandler
{
   private  HttpHandler next;

   public CookieSameSiteHandler(HttpHandler next){
      this.next = next;
   }

   @Override
   public void handleRequest(final HttpServerExchange exchange)
      throws Exception
   {
      exchange.addResponseCommitListener(serverExchange -> {
         for (Map.Entry<String, Cookie> responcecookie : serverExchange.getResponseCookies().entrySet()){
            serverExchange.getResponseCookies().replace(responcecookie.getKey(), proxyCookie(responcecookie.getValue()));
         }
      });
      next.handleRequest(exchange);
   }

   private Cookie proxyCookie(Cookie cookie)
   {
      return (Cookie)Proxy.newProxyInstance(
         cookie.getClass().getClassLoader(),
         cookie.getClass().getInterfaces(),
         (proxy, method, args) -> {
            if ("isSameSite".equals(method.getName())){
               return true;
            }
            if ("getSameSiteMode".equals(method.getName()) && cookie.getSameSiteMode() == null){
               return "None";
            }
            if ("isSecure".equals(method.getName()) && cookie.getSameSiteMode() == null){
               return true;
            }
            return method.invoke(cookie, args);
         });
   }
}

handler configuration:

<subsystem xmlns="urn:jboss:domain:undertow:7.0" default-virtual-host="default-host">
    <buffer-cache name="default"/>
    <server name="default-server" default-host="default-host">
        ...
        <host name="default-host" alias="localhost,example.com">
            ...
            <filter-ref name="cookiehandler"/>
            ...
        </host>
    </server>
    ...
    <filters>
        <filter class-name="nl.myownstuff.handler.CookieSameSiteHandler" module="nl.myownstuff.undertow" name="cookiehandler"/>
    </filters>
</subsystem>


来源:https://stackoverflow.com/questions/49697449/how-to-enable-samesite-for-jsessionid-cookie

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!