Spring Security中的相同站点Cookie

Tom*_*ála 5 security cookies spring-security jsessionid csrf-protection

在Spring Security中可以设置Same-site Cookie标志吗?请参阅:https : //tools.ietf.org/html/draft-west-first-party-cookies-07 ,如果没有,请问是否有增加支持的路线图?某些浏览器(例如Chrome)已经支持。TH

GKi*_*lin 16

新的 Tomcat 版本通过TomcatContextCustomizer. 所以你应该只自定义 tomcat CookieProcessor,例如 Spring Boot:

@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
    @Bean
    public TomcatContextCustomizer sameSiteCookiesConfig() {
        return context -> {
            final Rfc6265CookieProcessor cookieProcessor = new Rfc6265CookieProcessor();
            cookieProcessor.setSameSiteCookies(SameSiteCookies.NONE.getValue());
            context.setCookieProcessor(cookieProcessor);
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

SameSiteCookies.NONE注意,cookie 也是Secure(使用 SSL),否则无法应用。

默认情况下,由于 Chrome 80 cookie 被视为SameSite=Lax!

请参阅Spring Boot 中的SameSite CookieSameSite cookie 食谱


对于 nginx 代理,它可以在 nginx 配置中轻松解决:

if ($scheme = http) {
    return 301 https://$http_host$request_uri;
}

proxy_cookie_path / "/; secure; SameSite=None";
Run Code Online (Sandbox Code Playgroud)


Shi*_*mar 9

而不是过滤器,在您的身份验证成功处理程序中,您可以通过这种方式提及。

@Override
public void onAuthenticationSuccess(
        HttpServletRequest request, HttpServletResponse response,
        Authentication authentication) throws IOException {
    response.setStatus(HttpServletResponse.SC_OK);
    clearAuthenticationAttributes(request);
    addSameSiteCookieAttribute(response);
    handle(request, response);
}

private void addSameSiteCookieAttribute(HttpServletResponse response) {
    Collection<String> headers = response.getHeaders(HttpHeaders.SET_COOKIE);
    boolean firstHeader = true;
    // there can be multiple Set-Cookie attributes
    for (String header : headers) {
        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"));
    }
}
Run Code Online (Sandbox Code Playgroud)

在其中一个答案中提到了这一点。我实施后找不到链接。


unw*_*ich 6

如果您可以获得HttpServletResponse.

然后你可以这样做:

response.setHeader("Set-Cookie", "key=value; HttpOnly; SameSite=strict")
Run Code Online (Sandbox Code Playgroud)

在 spring-security 中,您可以使用过滤器轻松完成此操作,这是一个示例:

public class CustomFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                       FilterChain chain) throws IOException, ServletException {
        HttpServletResponse resp = (HttpServletResponse) response;
        resp.setHeader("Set-Cookie", "locale=de; HttpOnly; SameSite=strict");
        chain.doFilter(request, response);
    }
}
Run Code Online (Sandbox Code Playgroud)

将此过滤器添加到您的 SecurityConfig 中,如下所示:

http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class)
Run Code Online (Sandbox Code Playgroud)

或通过 XML:

<http>
    <custom-filter after="BASIC_AUTH_FILTER" ref="myFilter" />
</http>

<beans:bean id="myFilter" class="org.bla.CustomFilter"/>
Run Code Online (Sandbox Code Playgroud)


小智 6

这里所有可能的解决方案对我来说都失败了。每次尝试过滤器或拦截器时,尚未添加 Set-Cookie 标头。我能够完成这项工作的唯一方法是添加 Spring Session 并将这个 bean 添加到我的一个@Configuration文件中:

@Bean
public CookieSerializer cookieSerializer() {
    DefaultCookieSerializer serializer = new DefaultCookieSerializer();
    serializer.setSameSite("none");
    return serializer;
}
Run Code Online (Sandbox Code Playgroud)

无论如何,希望这可以帮助我遇到同样情况的其他人。


Kac*_*cki 5

这是不可能的。Spring Session 支持此功能:https : //spring.io/blog/2018/10/31/spring-session-bean-ga-released

我想出了一个类似于 Ron 的解决方案。但有一件重要的事情需要注意:

跨站点使用的 Cookie 必须指定SameSite=None; Secure 启用包含在第三方上下文中。

所以我在标题中包含了Secure属性。此外,当您不使用它们时,您不必覆盖所有三个方法。仅在您实施HandlerInterceptor.

import org.apache.commons.lang.StringUtils;

public class CookiesInterceptor extends HandlerInterceptorAdapter {
    final String sameSiteAttribute = "; SameSite=None";
    final String secureAttribute = "; Secure";

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {

        addEtagHeader(request, response);

        Collection<String> setCookieHeaders = response.getHeaders(HttpHeaders.SET_COOKIE);

        if (setCookieHeaders == null || setCookieHeaders.isEmpty())
            return;

        setCookieHeaders
            .stream()
            .filter(StringUtils::isNotBlank)
            .map(header -> {
                if (header.toLowerCase().contains("samesite")) {
                    return header;
                } else {
                    return header.concat(sameSiteAttribute);
                }
            })
            .map(header -> {
                if (header.toLowerCase().contains("secure")) {
                    return header;
                } else {
                    return header.concat(secureAttribute);
                }
            })
            .forEach(finalHeader -> response.setHeader(HttpHeaders.SET_COOKIE, finalHeader));
    }
}
Run Code Online (Sandbox Code Playgroud)

我在我的项目中使用了 xml,所以我不得不将它添加到我的配置文件中:

<mvc:interceptors>
    <bean class="com.zoetis.widgetserver.mvc.CookiesInterceptor"/>
</mvc:interceptors>
Run Code Online (Sandbox Code Playgroud)