jessessionId cookie 的 Samesite 只能从响应中设置
Posted
技术标签:
【中文标题】jessessionId cookie 的 Samesite 只能从响应中设置【英文标题】:Samesite for jessessionId cookie can be set only from response 【发布时间】:2021-01-12 02:47:03 【问题描述】:我正在尝试将相同站点设置为无;从 java filter 保护我的 jsessionid cookie。我已在响应集 cookie 标头中添加了此内容。更改后,请求 cookie jsessionId 相同。在响应中,jsessionId 被修改为 Samesite 属性 None 和安全。如果请求 jsessionId cookie 保持不变,它会起作用吗?
【问题讨论】:
检查这个使用GenericFilterBean / 临时重定向请求来解决同类问题***.com/questions/63939078/… 【参考方案1】:调用 ServletResponse 方法:sendError、getWrite.flush()、sendRedirect、getOutputStream.Flush 提交响应,这意味着状态代码和标头将在 Set-cookie 标头更新之前写入。 ServletResponse.
解决方案 1:您可以将过滤器放在任何可能导致调用上述方法的过滤器之前,并在调用 filterChain.doFilter 之前修改标题
解决方案 2:在提交响应之前拦截对此方法的调用并更新标头。
package com.cookie.example.filters.cookie;
import com.google.common.net.HttpHeaders;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.filter.DelegatingFilterProxy;
import javax.annotation.Nonnull;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Implementation of an HTTP filter @link Filter which which allow customization of @literal Set-Cookie header.
* customization is delegated to implementations of @link CookieHeaderCustomizer
*/
public class CookieHeaderCustomizerFilter extends DelegatingFilterProxy implements InitializingBean
private final List<CookieHeaderCustomizer> cookieHeaderCustomizers;
@Override
public void afterPropertiesSet() throws ServletException
super.afterPropertiesSet();
if(CollectionUtils.isEmpty(cookieHeaderCustomizers))
throw new IllegalArgumentException("cookieHeaderCustomizers is mandatory");
public CookieHeaderCustomizerFilter(final List<CookieHeaderCustomizer> cookieHeaderCustomizers)
this.cookieHeaderCustomizers = cookieHeaderCustomizers;
public CookieHeaderCustomizerFilter()
this.cookieHeaderCustomizers = Collections.emptyList();
/** @inheritDoc */
public void destroy()
/** @inheritDoc */
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException
if (!(request instanceof HttpServletRequest))
throw new ServletException("Request is not an instance of HttpServletRequest");
if (!(response instanceof HttpServletResponse))
throw new ServletException("Response is not an instance of HttpServletResponse");
chain.doFilter(request, new CookieHeaderResponseWrapper((HttpServletRequest) request, (HttpServletResponse)response ));
/**
* An implementation of the @link HttpServletResponse which customize @literal Set-Cookie
*/
private class CookieHeaderResponseWrapper extends HttpServletResponseWrapper
@Nonnull private final HttpServletRequest request;
@Nonnull private final HttpServletResponse response;
public CookieHeaderResponseWrapper(@Nonnull final HttpServletRequest req, @Nonnull final HttpServletResponse resp)
super(resp);
this.request = req;
this.response = resp;
/** @inheritDoc */
@Override
public void sendError(final int sc) throws IOException
applyCustomizers();
super.sendError(sc);
/** @inheritDoc */
@Override
public PrintWriter getWriter() throws IOException
applyCustomizers();
return super.getWriter();
/** @inheritDoc */
@Override
public void sendError(final int sc, final String msg) throws IOException
applyCustomizers();
super.sendError(sc, msg);
/** @inheritDoc */
@Override
public void sendRedirect(final String location) throws IOException
applyCustomizers();
super.sendRedirect(location);
/** @inheritDoc */
@Override
public ServletOutputStream getOutputStream() throws IOException
applyCustomizers();
return super.getOutputStream();
private void applyCustomizers()
final Collection<String> cookiesHeaders = response.getHeaders(HttpHeaders.SET_COOKIE);
boolean firstHeader = true;
for (final String cookieHeader : cookiesHeaders)
if (StringUtils.isBlank(cookieHeader))
continue;
String customizedCookieHeader = cookieHeader;
for(CookieHeaderCustomizer cookieHeaderCustomizer : cookieHeaderCustomizers)
customizedCookieHeader = cookieHeaderCustomizer.customize(request, response, customizedCookieHeader);
if (firstHeader)
response.setHeader(HttpHeaders.SET_COOKIE,customizedCookieHeader);
firstHeader=false;
else
response.addHeader(HttpHeaders.SET_COOKIE, customizedCookieHeader);
/**
* Implement this interface and inject add it to @link SameSiteCookieHeaderCustomizer
*/
public interface CookieHeaderCustomizer
String customize(@Nonnull final HttpServletRequest request, @Nonnull final HttpServletResponse response, @Nonnull final String cookieHeader);
package com.cookie.example.filters.cookie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*Add SameSite attribute if not already exist
*SameSite attribute value is defined by property "cookie.sameSite"
*/
public class SameSiteCookieHeaderCustomizer implements CookieHeaderCustomizer
private static final Logger LOGGER = LoggerFactory.getLogger(SameSiteCookieHeaderCustomizer.class);
private static final String SAME_SITE_ATTRIBUTE_NAME ="SameSite";
private static final String SECURE_ATTRIBUTE_NAME="Secure";
private final SameSiteValue sameSiteValue;
public SameSiteCookieHeaderCustomizer(SameSiteValue sameSiteValue)
this.sameSiteValue = sameSiteValue;
@Override
public String customize(@Nonnull final HttpServletRequest request, @Nonnull final HttpServletResponse response, @Nonnull final String cookieHeader)
StringBuilder sb = new StringBuilder(cookieHeader);
if (!cookieHeader.contains(SAME_SITE_ATTRIBUTE_NAME))
sb.append("; ").append(SAME_SITE_ATTRIBUTE_NAME).append("=").append(sameSiteValue.value);
if(SameSiteValue.None == sameSiteValue && !cookieHeader.contains(SECURE_ATTRIBUTE_NAME))
sb.append("; ").append(SECURE_ATTRIBUTE_NAME);
return sb.toString();
public enum SameSiteValue
/**
* Send the cookie for 'same-site' requests only.
*/
Strict("Strict"),
/**
* Send the cookie for 'same-site' requests along with 'cross-site' top
* level navigations using safe HTTP methods (GET, HEAD, OPTIONS, and TRACE).
*/
Lax("Lax"),
/**
* Send the cookie for 'same-site' and 'cross-site' requests.
*/
None("None");
/** The same-site attribute value.*/
private String value;
/**
* Constructor.
*
* @param attrValue the same-site attribute value.
*/
SameSiteValue(@Nonnull final String attrValue)
value = attrValue;
/**
* Get the same-site attribute value.
*
* @return Returns the value.
*/
public String getValue()
return value;
【讨论】:
以上是关于jessessionId cookie 的 Samesite 只能从响应中设置的主要内容,如果未能解决你的问题,请参考以下文章