SameSite cookie in Java application

后端 未结 9 1966
没有蜡笔的小新
没有蜡笔的小新 2020-12-24 01:08

Do you know any Java cookie implementation which allows to set a custom flag for cookie, like SameSite=strict? It seems that javax.servlet.http.Cookie has a str

相关标签:
9条回答
  • 2020-12-24 01:16

    Jetty server version 9.4.26.v20200117 allows for setting the SameSite attribute on the cookie. I had to do some digging around but this works.

    import static org.eclipse.jetty.http.HttpCookie.SAME_SITE_STRICT_COMMENT;
    
    ...
    
    Cookie cookie = new Cookie("my-cookie", "some-value");
    cookie.setMaxAge(120); // age in seconds
    cookie.setSecure(true);
    cookie.setHttpOnly(true);
    cookie.setComment(SAME_SITE_STRICT_COMMENT);
    
    response.addCookie(cookie);
    

    The addCookie() method on jetty servers's Response object does a check on the comment to add the SameSite attribute.

    0 讨论(0)
  • 2020-12-24 01:17

    As of today (24.01.20) servlet-api does not let to set sameSite attribute to the cookie. BTW there is an ongoing ticket (LINK) which will release a new (5.0 or 5.1 servlet-api).

    Option 1: You are not in a hurry and can wait for servlet-api version, where Cookie class and SessionCookieConfig class have dedicated methods to set sameSite attribute.

    Option 2: You are using an old version of servlet-api (e.g. 3.1), consequently old version of Tomcat (e.g. I am having current situation now). It means even when community releases servlet-api with sameSite support, you can not immediately update you version, because it can be too risky to update couple of major versions.
    In this case we have found a solution.
    There is a Cookie Processor ComponentLINK in Tomcat, which

    The CookieProcessor element represents the component that parses received cookie headers into javax.servlet.http.Cookie objects accessible through HttpServletRequest.getCookies() and converts javax.servlet.http.Cookie objects added to the response through HttpServletResponse.addCookie() to the HTTP headers returned to the client.

    The usage of this processor is quite straight forward. Inside of context.xml:

    <Context>
        ...
        <CookieProcessor sameSiteCookies="none"/>
    </Context>
    

    In this case default implementation of processor is used (org.apache.tomcat.util.http.Rfc6265CookieProcessor), but you can specify any other within an CookieProcessor attribute className.

    0 讨论(0)
  • 2020-12-24 01:20

    If using spring boot with Tom cat then this has been answered in another question. In summary, set the attribute on the tom cat config. This is global, all cookies will then have same site enabled. (from the other question https://stackoverflow.com/a/60860531/400048)

    @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);
        };
      }
    
    0 讨论(0)
  • 2020-12-24 01:22

    If you don't wanna update all your code, you can also achieve same by one line config using Apache or Nginx configuration(or any other HTTP server/proxy that you are using)

    1 Setting SameSite cookies using Apache configuration

    You can add the following line to your Apache configuration

    Header always edit Set-Cookie (.*) "$1; SameSite=Lax"
    

    and this will update all your cookies with SameSite=Lax flag

    See more here: https://blog.giantgeek.com/?p=1872

    2 Setting SameSite cookies using Nginx configuration

    location / {
        # your usual config ...
        # hack, set all cookies to secure, httponly and samesite (strict or lax)
        proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
    }
    

    Same here, this also will update all your cookies with SameSite=Lax flag

    See more here: https://serverfault.com/questions/849888/add-samesite-to-cookies-using-nginx-as-reverse-proxy

    0 讨论(0)
  • 2020-12-24 01:23

    I tried the listed solutions for using javax.servlet.http.Cookie to set the SameSite=strict attribute, but none of them worked.

    However, this way worked for me, using javax.servlet.http.Cookie (JRE 1.8 + JBOSS 7.X) :

    Cookie cookie = new Cookie(name, value);
    path = path.concat("SameSite=Strict;");
    cookie.setPath(path);
    

    That's it. tested on

    • Google Chrome Version 81.0.4044.129 (Official Build) (64-bit)
    • Microsoft Edge Version 81.0.416.68 (Official build) (64-bit)
    • Firefox 75.0 (64-bit)
    0 讨论(0)
  • 2020-12-24 01:25

    If you have existing code, no doubt you've used the java servlet Cookie object. We certainly have, so we wanted the least disruptive option. @kriegaex's answer is clean and concise, but is basically hard coding the cookie and doesn't reuse the cookie object. To expand on his answer, we wrote this function to handle the same site functionality, while at the same time, maintaining the existing Cookie object functionality. This answer is intended to be used in cases where you need to add multiple cookies on your response object, without making changes to existing cookies that may already be on the headers. The other option of course is to write a new cookie class and extend the functionality, but that requires even more changes to existing code than what we've come up with here.

    Note that with this solution, only one line of existing code (per cookie) changes in order to add the same site functionality.

    Sample usage:

    // Existing code that doesn't change:   
    Cookie cookie1=new Cookie("cookie1",Util.encodeURL(id));
    cookie1.setHttpOnly(false);
    cookie1.setPath("/");
    
    Cookie cookie2=new Cookie("cookie2",Util.encodeURL(id));
    cookie2.setHttpOnly(false);
    cookie2.setPath("/");
    
    // Old Code that is replaced by new code
    // httpResponse.addCookie(cookie1);
    // httpResponse.addCookie(cookie2);
    
    // New Code - see static helper class below
    HttpService.addCookie(httpResponse, cookie1, "none");
    HttpService.addCookie(httpResponse, cookie2, "Strict");
    

    Example response headers when using cURL:

    < HTTP/1.1 200 OK
    < Connection: keep-alive
    < X-Powered-By: Undertow/1
    < Set-Cookie: cookie1=f871c026e8eb418c9c612f0c7fe05b08; path=/; SameSite=none; secure
    < Set-Cookie: cookie2=51b405b9487f4487b50c80b32eabcc24; path=/; SameSite=Strict; secure
    < Server: WildFly/9
    < Transfer-Encoding: chunked
    < Content-Type: image/png
    < Date: Tue, 10 Mar 2020 01:55:37 GMT
    

    And finally, the static helper class:

    public class HttpService {
        private static final FastDateFormat expiresDateFormat= FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss zzz", TimeZone.getTimeZone("GMT"));
    
    
        public static void addCookie(HttpServletResponse response, Cookie cookie, String sameSite) {
    
            StringBuilder c = new StringBuilder(64+cookie.getValue().length());
    
            c.append(cookie.getName());
            c.append('=');
            c.append(cookie.getValue());
    
            append2cookie(c,"domain",   cookie.getDomain());
            append2cookie(c,"path",     cookie.getPath());
            append2cookie(c,"SameSite", sameSite);
    
            if (cookie.getSecure()) {
                c.append("; secure");
            }
            if (cookie.isHttpOnly()) {
                c.append("; HttpOnly");
            }
            if (cookie.getMaxAge()>=0) {
                append2cookie(c,"Expires", getExpires(cookie.getMaxAge()));
            }
    
            response.addHeader("Set-Cookie", c.toString());
        }
    
        private static String getExpires(int maxAge) {
            if (maxAge<0) {
                return "";
            }
            Calendar expireDate = Calendar.getInstance();
            expireDate.setTime(new Date());
            expireDate.add(Calendar.SECOND,maxAge);
    
            return expiresDateFormat.format(expireDate);
        }
    
        private static void append2cookie(StringBuilder cookie, String key, String value) {
            if (key==null || 
                    value==null || 
                    key.trim().equals("") 
                    || value.trim().equals("")) {
                return;
            }
    
            cookie.append("; ");
            cookie.append(key);
            cookie.append('=');
            cookie.append(value);
        }
    }
    
    0 讨论(0)
提交回复
热议问题