set httpOnly and secure flags on session cookie in Google App Engine

前端 未结 3 556
后悔当初
后悔当初 2020-12-11 07:32

I need to set httpOnly and secure flags on session cookie in Google App Engine.

I tried the following in web.xml:

         


        
相关标签:
3条回答
  • 2020-12-11 08:07

    I had the very same problem with Google App Engine, using Java 7 and Servlet 2.5, to add HttpOnly and Secure attributes to session cookies. I followed @bat_venti 's answer - which helped very much, thank you! - but had some trouble to make it work, so I'm posting my own answer :)

    I created a SecurityFilter class to apply the session cookies attributes to .jsp requests, just like the following:

    import javax.servlet.*;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletResponseWrapper;
    import java.io.IOException;
    
    public class SecurityFilter implements javax.servlet.Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {}
    
        @Override
        public void destroy() {}
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            // wrap the response
            response = new SecureCookieSetter((HttpServletResponse)response);
    
            // touch the session
            ((HttpServletRequest) request).getSession();
    
            // overwriting the cookie with Secure and HttpOnly attribute set
            ((HttpServletResponse)response).setHeader("Set-Cookie", "JSESSIONID=" + ((HttpServletRequest)request).getSession().getId() + ";Path=/");
    
            chain.doFilter(request, response);
        }
    
        public class SecureCookieSetter extends HttpServletResponseWrapper {
    
            public SecureCookieSetter(HttpServletResponse response) {
                super(response);
            }
    
            @Override
            public void addCookie(Cookie cookie) {
                cookie.setSecure(true);
                super.addCookie(cookie);
            }
    
            @Override
            public void addHeader(String name, String value) {
                if ((name.equals("Set-Cookie")) && (!value.matches("(^|.*;)\\s*Secure"))) {
                    value = value + ";Secure;HttpOnly";
                }
                super.addHeader(name, value);
            }
    
            @Override
            public void setHeader(String name, String value) {
                if ((name.equals("Set-Cookie")) && (!value.matches("(^|.*;)\\s*Secure"))) {
                    value = value + ";Secure;HttpOnly";
                }
                super.setHeader(name, value);
            }
    
        }
    }
    

    (I created the SecureCookieSetter class internally, because I would only use it in this filter, but feel free to put it on its own file).

    After that, I edited the web.xml file to use the filter whenever a .jsp file is requested:

    <web-app>
    ...
        <filter>
            <filter-name>SecurityFilter</filter-name>
            <filter-class>path.to.my.filter.SecurityFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>SecurityFilter</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
    ...
    </web-app>
    

    (Obviously, replacing path.to.my.filter for the real location of your class file).

    0 讨论(0)
  • 2020-12-11 08:10

    I had the same problem with Google App Engine, but I wanted to add Secure attribute to all cookies. The following shows how I've added Secure attribute to all cookies. I'm almost sure that this solution will work for you just by substituting Secure with HttpOnly.

    I've implemented a security filter and made a mapping to the pages that I want the Secure attribute be set.

    <filter>
        <filter-name>Security Filter</filter-name>
        <filter-class>common.SecurityFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Security Filter</filter-name>
        <url-pattern>*.jsf</url-pattern>
    </filter-mapping>
    

    My first try was to wrap the response into my custom HttpServletResponseWrapper. All was fine except the session cookie doesn't get the attribute. I debugged around and found that the session cookie is not added using the mechanism I've expected. I've then noticed that after you touch the session the session cookie is magically added to the response headers e.g. the headers now consists the line Set-Cookie: JSESSIONID=abcdef;Path=/ but the cookie wasn't added using the wrapper object that I've created. I've figured out that after I've touched the session I can set the cookie that I want with the attributes that I want. So the workaround was easy.

    public class SecurityFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            // wrap the response
            response = new SecureCookieSetter((HttpServletResponse)response);
    
            // touch the session
            (HttpServletRequest)request.getSession();
    
            // overwriting the cookie with Secure attribute set
            ((HttpServletResponse)response).setHeader("Set-Cookie", "JSESSIONID=" + ((HttpServletRequest)request).getSession().getId() + ";Path=/");
        }
    }
    
    public class SecureCookieSetter extends HttpServletResponseWrapper {
    
        public SecureCookieSetter(HttpServletResponse response) {
            super(response);
        }
    
        @Override
        public void addCookie(Cookie cookie) {
            cookie.setSecure(true);
            super.addCookie(cookie);
        }
    
        @Override
        public void addHeader(String name, String value) {
            if ((name.equals("Set-Cookie")) && (!value.matches("(^|.*;)\\s*Secure"))) {
                value = value + ";Secure";
            }
            super.addHeader(name, value);
        }
    
        @Override
        public void setHeader(String name, String value) {
            if ((name.equals("Set-Cookie")) && (!value.matches("(^|.*;)\\s*Secure"))) {
                value = value + ";Secure";
            }
            super.setHeader(name, value);
        }
    
    }
    
    0 讨论(0)
  • 2020-12-11 08:12

    In my case the SecureCookieSetter class is not getting used. I also have my java web app running into the GAE. Below is code which is working fine in my case. Also its always recommeded to have other security related headers like max-age and others as below.

    package com.securityFilter;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.log4j.Logger;
    
    import com.filters.XSSRequestWrapper;
    
    public class SecurityFilter implements Filter   {
    
        protected static final Logger log = Logger.getLogger(SecurityFilter.class);
    
        private static final String PRAGMA_KEY = "Pragma";
        private static final String PRAGMA_VALUE = "no-cache";
    
        private static final String STRICT_TRANSPORT_KEY = "strict-transport-security";
        private static final String STRICT_TRANSPORT_VALUE = "max-age=604800";
    
        private static final String SET_COOKIE = "Set-Cookie";
        private static final String JSESSION_ID = "JSESSIONID=";
        private static final String HTTP_ONLY = ";Secure;HttpOnly";
    
        private static final String CACHE_CONTROL_KEY = "Cache-Control";
        private static final String CACHE_CONTROL_VALUE = "no-store";
    
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            makeCookieSecured(response, httpServletRequest);    
            chain.doFilter(request, response);
    
        }
    
        private void makeCookieSecured(ServletResponse response,
                HttpServletRequest httpServletRequest) {
            Cookie[] cookies = httpServletRequest.getCookies();
            HttpServletResponse httpResp = ((HttpServletResponse) response);
            if (cookies != null) {
                for(Cookie cookie :cookies){
                    if("JSESSIONID".equals(cookie.getName())) {
                        cookie.setValue(httpServletRequest.getSession().getId() + HTTP_ONLY);
                        cookie.setSecure(true);
                        cookie.setPath("/");
                        cookie.setMaxAge(604800);
                    }
                }
            }
            httpResp.setHeader(SET_COOKIE, JSESSION_ID + httpServletRequest.getSession().getId() + HTTP_ONLY);
            httpResp.setHeader(CACHE_CONTROL_KEY, CACHE_CONTROL_VALUE);
            httpResp.setHeader(PRAGMA_KEY, PRAGMA_VALUE);
            httpResp.setHeader(STRICT_TRANSPORT_KEY, STRICT_TRANSPORT_VALUE);
        }
    
        private void createJSONErrorResponse(ServletResponse response)
                throws IOException {
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write("Please provide valid input, You might have provided some special characters which is not allowed");
        }
    
        @Override 
        public void destroy() {
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题