Samesite for jessessionId cookie can be set only from response

后端 未结 1 1064
轻奢々
轻奢々 2021-01-26 09:02

I am trying to set samesite none; secure for my jsessionid cookie from java filter . I have added this in response set cookie header.After this change the request cookie jsessio

相关标签:
1条回答
  • 2021-01-26 09:47

    A call to ServletResponse methods: sendError, getWrite.flush(), sendRedirect, getOutputStream.Flush commits the response, meaning the status code and headers will be written before update of the Set-cookie header. ServletResponse.

    Solution 1 : you can place your filter before any filter which could cause a call to the method mentioned above and modify the headers before the call to filterChain.doFilter

    Solution 2 : Intercept calls to this method and update headers before the response is committed.

        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;
          }
      
        }
      
      }
    
    0 讨论(0)
提交回复
热议问题