Security 如何为jsessionid cookie启用samesite

Security 如何为jsessionid cookie启用samesite,security,web,cookies,wildfly-10,Security,Web,Cookies,Wildfly 10,如何为在wildfly上运行的web应用程序启用samesite。 选中了standalone.xml,但在中找不到合适的标记 目前,Java Servlet 4.0规范不支持SameSite cookie属性。您可以通过打开java类来查看可用的属性 然而,有几个变通办法。您可以手动覆盖设置Cookie属性 方法#1(使用定制的Spring HttpFirewall和包装请求): 您需要在创建会话后立即包装请求并调整cookies。您可以通过定义以下类来实现: 一个bean(如果你想把所有东西

如何为在wildfly上运行的web应用程序启用samesite。 选中了
standalone.xml
,但在中找不到合适的标记


目前,Java Servlet 4.0规范不支持SameSite cookie属性。您可以通过打开java类来查看可用的属性

然而,有几个变通办法。您可以手动覆盖设置Cookie属性

方法#1(使用定制的Spring HttpFirewall和包装请求):

您需要在创建会话后立即包装请求并调整cookies。您可以通过定义以下类来实现:

一个bean(如果你想把所有东西都放在一个地方,你可以在SecurityConfig中定义它。为了简洁起见,我在它上面加了@Component注释)

包hello.approach 1;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
导入org.springframework.security.web.firewall.FirewalledRequest;
导入org.springframework.security.web.firewall.HttpFirewall;
导入org.springframework.security.web.firewall.RequestRejectedException;
导入org.springframework.stereotype.Component;
@组成部分
公共类CustomHttpFirewall实现HttpFirewall{
@凌驾
公共FirewalledRequest getFirewalledRequest(HttpServletRequest请求)抛出RequestRejectedException{
返回新的RequestWrapper(请求);
}
@凌驾
公共HttpServletResponse获取防火墙响应(HttpServletResponse){
返回新的ResponseWrapper(response);
}
}
第一包装类

包hello.approach 1;
导入java.util.Collection;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
导入javax.servlet.http.HttpSession;
导入org.springframework.http.HttpHeaders;
导入org.springframework.security.web.firewall.FirewalledRequest;
导入org.springframework.web.context.request.RequestContextHolder;
导入org.springframework.web.context.request.ServletRequestAttributes;
/**
*围绕HttpServletRequest的包装器,覆盖Set-Cookie响应头并添加SameSite=None部分。
*/
公共类RequestWrapper扩展了FirewalledRequest{
/**
*构造一个封装给定请求的请求对象。
*
*@param请求包装请求
*如果请求为空,@将引发IllegalArgumentException
*/
公共请求包装器(HttpServletRequest请求){
超级(请求);
}
/**
*在Spring引导中默认情况下必须为空。请参阅FirewalledRequest。
*/
@凌驾
公共无效重置(){
}
@凌驾
公共HttpSession getSession(布尔创建){
HttpSession session=super.getSession(创建);
如果(创建){
ServletRequestAttributes ra=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
如果(ra!=null){
覆盖setBookie(ra.getResponse());
}
}
返回会议;
}
@凌驾
公共字符串changeSessionId(){
字符串newSessionId=super.changeSessionId();
ServletRequestAttributes ra=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
如果(ra!=null){
覆盖setBookie(ra.getResponse());
}
返回newSessionId;
}
私有void overwritescookie(HttpServletResponse){
if(响应!=null){
Collection headers=response.getHeaders(HttpHeaders.SET\u COOKIE);
布尔值firstHeader=true;
对于(字符串头:头){//可以有多个集Cookie属性
如果(第一个标题){
response.setHeader(HttpHeaders.SET_COOKIE,String.format(“%s;%s”,header,“SameSite=None”);//SET
firstHeader=false;
继续;
}
response.addHeader(HttpHeaders.SET_COOKIE,String.format(“%s;%s”,header,“SameSite=None”);//添加
}
}
}
}
第二包装类

包hello.approach 1;
导入javax.servlet.http.HttpServletResponse;
导入javax.servlet.http.HttpServletResponseWrapper;
/**
*虚拟实现。
*要与RequestWrapper对齐。
*/
公共类ResponseWrapper扩展了HttpServletResponseWrapper{
/**
*构造一个封装给定响应的响应适配器。
*
*@param response要包装的响应
*如果响应为空,@将引发IllegalArgumentException
*/
公共响应包装器(HttpServletResponse){
超级(响应);
}
}
方法#2(使用Spring的AuthenticationSuccessHandler):

这种方法不适用于基本身份验证。 在基本身份验证的情况下,响应在控制器返回响应对象之后,在调用AuthenticationSuccessHandlerImpl#addSameSiteCookieAttribute之前立即刷新/提交

package hello.approach 2;
导入java.io.IOException;
导入java.util.Collection;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
导入org.springframework.http.HttpHeaders;
导入org.springframework.security.core.Authentication;
导入org.springframework.security.web.authentication.AuthenticationSuccessHandler;
公共类AuthenticationSuccessHandlerImpl实现AuthenticationSuccessHandler{
@凌驾
AuthenticationSuccess(HttpServletRequest请求、HttpServletResponse响应、身份验证)上的公共void引发IOException{
addSameSiteCookieAttribute(响应);//添加SameSite=strict以设置Cookie属性
response.sendRedirect(“/hello”);//验证成功后重定向到hello.html
}
私有void addSameSiteCookieAttribute(HttpServletResponse){
收集
<Context>
   <CookieProcessor sameSiteCookies="strict" />
</Context>
 ./bin/standalone.sh -Dio.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION=true
@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);
            }
        });
    }
}
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);
         });
   }
}
<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>
$ cat src/main/webapp/WEB-INF/undertow-handlers.conf
samesite-cookie(mode=Lax)
path(/app2)->samesite-cookie(mode=Lax, cookie-pattern=abc*)
<Context>
   <CookieProcessor sameSiteCookies="strict" />
</Context>