4

我需要在 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");

我怎样才能做到这一点?

4

3 回答 3

7

我在使用 Google App Engine 时遇到了同样的问题,但我想Secure为所有 cookie 添加属性。下面显示了我如何Secure为所有 cookie 添加属性。我几乎可以肯定,这个解决方案只需SecureHttpOnly.

我已经实现了一个安全过滤器并映射到我想要设置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>

我的第一次尝试是将响应包装到我的 customHttpServletResponseWrapper中。一切都很好,只是会话 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);
    }

}
于 2013-05-17T19:07:20.550 回答
4

我在使用 Java 7 和 Servlet 2.5 向会话 cookie 添加HttpOnlySecure属性时遇到了与 Google App Engine 相同的问题。我关注了@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为您的类文件的实际位置)。

于 2018-10-15T18:49:20.660 回答
1

在我的情况下,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 {
    }

}
于 2018-10-18T08:50:46.987 回答