在Google App Engine中设置会话cookie上的httpOnly和安全标志

时间:2013-05-06 12:01:50

标签: google-app-engine servlets session-cookies

我需要在Google App Engine中的会话cookie上设置httpOnly和安全标记。

我在web.xml中尝试了以下内容:

<session-config>
 <cookie-config>
  <http-only>true</http-only>
 </cookie-config>
</session-config>

但是,这不起作用。

我也在每个JSP的顶部尝试过这个:

String sessionid = request.getSession().getId();
response.setHeader("SET-COOKIE", "JSESSIONID=" + sessionid + "; HttpOnly");

我怎样才能做到这一点?

3 个答案:

答案 0 :(得分:6)

我在使用Google App Engine时遇到了同样的问题,但我想在所有Cookie中添加Secure属性。以下显示了我如何为所有Cookie添加Secure属性。我几乎可以肯定,只需用Secure代替HttpOnly,这个解决方案就能为您服务。

我已经实现了一个安全过滤器并映射到了我希望设置Secure属性的页面。

<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>

我的第一次尝试是将回复包装到我的自定义HttpServletResponseWrapper中。一切都很好,除了会话cookie没有得到属性。我调试了一下,发现会话cookie没有使用我预期的机制添加。我注意到,在您触摸会话后,会话cookie被神奇地添加到响应标头中,例如标题现在由行Set-Cookie: JSESSIONID=abcdef;Path=/组成,但是没有使用我创建的包装器对象添加cookie。我已经发现,在我触及会话后,我可以使用我想要的属性设置我想要的cookie。所以解决方法很简单。

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);
    }

}

答案 1 :(得分:1)

我在使用Java 7和Servlet 2.5的Google App Engine中遇到了同样的问题,即将HttpOnlySecure属性添加到会话Cookie中。我遵循了@bat_venti的回答-很有帮助,谢谢! -但在使其工作时遇到了一些麻烦,所以我要发布自己的答案:)

我创建了一个SecurityFilter类,将会话cookie属性应用于.jsp请求,如下所示:

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);
        }

    }
}

(我在内部创建了SecureCookieSetter类,因为我只会在此过滤器中使用它,但是可以将其放在自己的文件中)。

之后,我编辑了web.xml文件以在请求.jsp文件时使用过滤器:

<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>

(显然,将path.to.my.filter替换为类文件的实际位置)。

答案 2 :(得分:0)

就我而言,SecureCookieSetter类没有被使用。我还将我的Java Web应用程序运行到GAE中。 下面是在我的情况下工作正常的代码。同样,它总是建议使用其他与安全性相关的标头,例如max-age和以下标头。

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 {
    }

}