首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为jsessionid cookie启用samesite

如何为jsessionid cookie启用samesite
EN

Stack Overflow用户
提问于 2018-04-07 00:40:09
回答 6查看 43.6K关注 0票数 21

如何为在wildfly as上运行的web应用程序启用samesite。但是,Checked standalone.xml无法在其中找到适当的标签

代码语言:javascript
复制
<servlet-container name="default">
    <session-cookie http-only="true" secure="true"/>
    <jsp-config/>
</servlet-container>
EN

回答 6

Stack Overflow用户

发布于 2018-07-29 07:44:32

到目前为止,Java servlet4.0规范不支持SameSite cookie属性。您可以通过打开javax.servlet.http.Cookie java类来查看可用的属性。

但是,有几个变通方法。您可以手动覆盖Set-Cookie属性。

Spring方法#1 (在请求周围使用自定义 HttpFirewall和包装器):

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

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

代码语言:javascript
复制
package hello.approach1;

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

import org.springframework.security.web.firewall.FirewalledRequest;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.RequestRejectedException;
import org.springframework.stereotype.Component;

@Component
public class CustomHttpFirewall implements HttpFirewall {

    @Override
    public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
        return new RequestWrapper(request);
    }

    @Override
    public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
        return new ResponseWrapper(response);
    }

}

第一个包装器类

代码语言:javascript
复制
package hello.approach1;

import java.util.Collection;

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

import org.springframework.http.HttpHeaders;
import org.springframework.security.web.firewall.FirewalledRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * Wrapper around HttpServletRequest that overwrites Set-Cookie response header and adds SameSite=None portion.
 */
public class RequestWrapper extends FirewalledRequest {

    /**
     * Constructs a request object wrapping the given request.
     *
     * @param request The request to wrap
     * @throws IllegalArgumentException if the request is null
     */
    public RequestWrapper(HttpServletRequest request) {
        super(request);
    }

    /**
     * Must be empty by default in Spring Boot. See FirewalledRequest.
     */
    @Override
    public void reset() {
    }

    @Override
    public HttpSession getSession(boolean create) {
        HttpSession session = super.getSession(create);

        if (create) {
            ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (ra != null) {
                overwriteSetCookie(ra.getResponse());
            }
        }

        return session;
    }

    @Override
    public String changeSessionId() {
        String newSessionId = super.changeSessionId();
        ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (ra != null) {
            overwriteSetCookie(ra.getResponse());
        }
        return newSessionId;
    }

    private void overwriteSetCookie(HttpServletResponse response) {
        if (response != null) {
            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=None")); // set
                    firstHeader = false;
                    continue;
                }
                response.addHeader(HttpHeaders.SET_COOKIE, String.format("%s; %s", header, "SameSite=None")); // add
            }
        }
    }
}

第二个包装器类

代码语言:javascript
复制
package hello.approach1;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * Dummy implementation.
 * To be aligned with RequestWrapper.
 */
public class ResponseWrapper extends HttpServletResponseWrapper {
    /**
     * Constructs a response adaptor wrapping the given response.
     *
     * @param response The response to be wrapped
     * @throws IllegalArgumentException if the response is null
     */
    public ResponseWrapper(HttpServletResponse response) {
        super(response);
    }
}

Spring2方法(使用的AuthenticationSuccessHandler):

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

代码语言:javascript
复制
package hello.approach2;

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"));
        }
    }
}

方法#3 (使用javax.servlet.Filter):

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

代码语言:javascript
复制
package hello.approach3;

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() {

    }
}

方法#4 (如果您使用的是Tomcat9.0.21/Tomcat8.5.42或更高版本)

在您的web应用程序中,在META-INF文件夹中创建一个包含以下内容的context.xml文件:

代码语言:javascript
复制
<Context>
   <CookieProcessor sameSiteCookies="strict" />
</Context>

从Tomcat9.0.28/Tomcat8.5.48开始,可以将SameSite设置为none )

有关更多详细信息,请参阅this pull request

演示项目

您可以在GitHub上查看this demo project,了解有关前3种方法配置的更多详细信息。

SecurityConfig包含所有必要的配置。

使用addHeader的

不能保证正常工作,因为Servlet容器基本上管理会话和Cookie的创建。例如,如果您在响应正文中返回JSON,则第二种和第三种方法将不起作用,因为应用程序服务器将在刷新响应期间覆盖Set-Cookie头。但是,第二种和第三种方法适用于在身份验证成功后将用户重定向到另一个页面的情况。请注意,Postman不会呈现/支持cookie部分下的SameSite cookie属性(至少在撰写本文时是这样)。您可以查看Set-Cookie响应头或使用curl查看是否添加了SameSite cookie属性。

票数 28
EN

Stack Overflow用户

发布于 2019-05-17 14:58:16

一种解决方法是使用另一个属性(例如comment)将SameSite设置修改到cookie中:

代码语言:javascript
复制
<servlet-container name="default">
    <jsp-config/>
    <session-cookie comment="; SameSite=None"/>
    <websockets/>
</servlet-container>

但是,由于Undertow在使用版本0或版本1cookie时会引用注释(和其他)值,因此需要在将io.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION系统属性设置为true的情况下运行JBoss/WildFly

代码语言:javascript
复制
 ./bin/standalone.sh -Dio.undertow.cookie.DEFAULT_ENABLE_RFC6265_COOKIE_VALIDATION=true

这将为您提供所需的结果:

这种方法显然很老套,完全依赖于Undertow实现细节,所以我建议在web服务器或负载均衡器级别上进行配置。

票数 8
EN

Stack Overflow用户

发布于 2020-02-25 16:37:40

对于当前最新版本的Spring Boot:

如果您没有最新的spring-boot-starter-tomcat,请检查SameSiteCookies枚举中的值UNSET,如果缺少该值,则需要一个较新的版本,因为它将跳过值SameSite=None

代码语言:javascript
复制
@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);
            }
        });
    }
}
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49697449

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档