首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Spring中设置相同站点的cookie标志?

问如何在Spring中设置相同站点的cookie标志?
EN

Stack Overflow用户
提问于 2019-10-15 01:34:51
回答 8查看 51.6K关注 0票数 22

是否可以在Spring中设置同址琦琦标志?

我的Chrome问题:

与http://google.com/的跨站点资源关联的cookie是在没有SameSite属性的情况下设置的。Chrome的未来版本只有在SameSite=None和Secure的情况下,才会提供带有跨站点请求的cookie。您可以在Application>Storage>Cookies下查看开发人员工具中的cookie,并在https://www.chromestatus.com/feature/5088147346030592和https://www.chromestatus.com/feature/5633521622188032上查看更多详细信息。

​

如何解决这个问题?

EN

回答 8

Stack Overflow用户

发布于 2021-05-03 08:56:49

弹簧启动2.6.0

SpringBoot2.6.0现在支持配置SameSite cookie属性:

通过属性配置

代码语言:javascript
复制
server.servlet.session.cookie.same-site=strict

通过代码进行配置

代码语言:javascript
复制
import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MySameSiteConfiguration {
    @Bean
    public CookieSameSiteSupplier applicationCookieSameSiteSupplier() {
        return CookieSameSiteSupplier.ofStrict();
    }
}

Spring Boot 2.5.0及以下

SpringBoot2.5.0-快照不支持SameSite cookie属性,也没有设置来启用它。

JavaServlet4.0规范不支持SameSite cookie属性。通过打开javax.servlet.http.Cookie java类,您可以看到可用的属性。

然而,有几个解决办法。您可以手动重写Set-Cookie属性。

第一种方法(使用自定义的Spring 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);
    }
}

第二种方法(使用Spring的AuthenticationSuccessHandler): )

这种方法不适用于基本身份验证。如果进行基本身份验证,则在控制器返回响应对象之后,在调用SameSiteFilter#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"));
        }
    }
}

第三种方法(使用javax.servlet.Filter):

这种方法不适用于基本身份验证。如果进行基本身份验证,则在控制器返回响应对象之后,在调用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() {

    }
}

有关org.springframework.security.web.authentication.AuthenticationSuccessHandler或javax.servlet.Filter配置的更多细节,您可以查看GitHub上的这个演示项目。

SecurityConfig包含所有必要的配置。

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

票数 12
EN

Stack Overflow用户

发布于 2019-10-21 13:50:51

这是Security (https://github.com/spring-projects/spring-security/issues/7537)的一个未决问题。

正如我在Spring (2.1.7.RELEASE)中检查的那样,默认情况下,它使用DefaultCookieSerializer,它将属性sameSite默认为Lax。

您可以通过以下代码在应用程序启动时修改此代码。

注意:这是一个黑客,直到一个真正的修复(配置)暴露在下一个春季发行版。

代码语言:javascript
复制
@Component
@AllArgsConstructor
public class SameSiteInjector {

  private final ApplicationContext applicationContext;

  @EventListener
  public void onApplicationEvent(ContextRefreshedEvent event) {
    DefaultCookieSerializer cookieSerializer = applicationContext.getBean(DefaultCookieSerializer.class);
    log.info("Received DefaultCookieSerializer, Overriding SameSite Strict");
    cookieSerializer.setSameSite("strict");
  }
}
票数 11
EN

Stack Overflow用户

发布于 2022-01-12 09:23:30

从春季引导版本2.6.+,您可以通过编程或通过配置文件指定您的samesite cookie。

SpringBoot2.6.0文档

如果您想通过配置文件将samesite设置为lax,那么:

代码语言:javascript
复制
server.servlet.session.cookie.same-site=lax

或按程序编制

代码语言:javascript
复制
@Configuration
public class MySameSiteConfiguration {

    @Bean
    public CookieSameSiteSupplier applicationCookieSameSiteSupplier() {
        return CookieSameSiteSupplier.ofLax();
    }

}
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58386069

复制
相关文章

相似问题

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