28

我有一个在 Tomcat 7 服务器上运行的 Web 应用程序。默认情况下,带有会话 id 的 cookie 具有标志HttpOnlySecure. 我想为JSESSIONIDcookie 禁用这个标志。但它不会工作。我已经在我的web.xml文件中更改了它,但它不起作用。

<session-config>
    <session-timeout>20160</session-timeout>
    <cookie-config>
        <http-only>false</http-only>
        <secure>false</secure>
    </cookie-config>
</session-config>

我知道这是一个安全风险,因为如果攻击者找到了 xss 漏洞,他就能够窃取 cookie 并劫持会话。

JSESSIONIDcookie 应该使用 HTTP 和 HTTPS 以及 AJAX 请求发送。

编辑:

HttpOnly通过向文件添加以下选项成功禁用了该标志conf/context.xml

<Context useHttpOnly="false">
....
</Context>
4

3 回答 3

2

如果你阅读tomcat的代码,你会发现:

// Always set secure if the request is secure
if (scc.isSecure() || secure) {
    cookie.setSecure(true);
}

因此,尝试sessionCookieConfig.setSecure(false);在侦听器或<cookie-config><secure>false</secure></cookie-config>web.xml 中停用 JSESSIONID cookie 上的安全标志将不起作用,因为如果请求是安全的(即来自 https url 或 SSL 端口),Tomcat 会强制安全标志为真。

一种解决方案是在会话创建后立即使用请求过滤器修改服务器响应上的 JSESSIONID cookie。这是我的实现(非常基本):

public class DisableSecureCookieFilter implements javax.servlet.Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if(request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
            request = new ForceUnsecureSessionCookieRequestWrapper((HttpServletRequest) request, (HttpServletResponse) response);
        }

        chain.doFilter(request, response);
    }

    @Override
    public void destroy() { }

    public static class ForceUnsecureSessionCookieRequestWrapper extends HttpServletRequestWrapper {
        HttpServletResponse response;

        public ForceUnsecureSessionCookieRequestWrapper(HttpServletRequest request, HttpServletResponse response) {
            super(request);
            this.response = response;
        }

        @Override
        public HttpSession getSession(boolean create) {
            if(create) {
                HttpSession session = super.getSession(create);
                updateCookie(response.getHeaders("Set-Cookie"));
                return session;
            }
            return super.getSession(create);
        }

        @Override
        public HttpSession getSession() {
            HttpSession session = super.getSession();
            if(session != null) {
                updateCookie(response.getHeaders("Set-Cookie"));
            }

            return session;
        }

        protected void updateCookie(Collection<String> cookiesAfterCreateSession) {
            if(cookiesAfterCreateSession != null && !response.isCommitted()) {
                // search if a cookie JSESSIONID Secure exists
                Optional<String> cookieJSessionId = cookiesAfterCreateSession.stream()
                                                        .filter(cookie -> cookie.startsWith("JSESSIONID") && cookie.contains("Secure"))
                                                        .findAny();
                if(cookieJSessionId.isPresent()) {
                    // remove all Set-Cookie and add the unsecure version of the JSessionId Cookie
                    response.setHeader("Set-Cookie", cookieJSessionId.get().replace("Secure", ""));

                    // re-add all other Cookies
                    cookiesAfterCreateSession.stream()
                            .filter(cookie -> !cookie.startsWith("JSESSIONID"))
                            .forEach(cookie -> response.addHeader("Set-Cookie", cookie));
                }
            }
        }
    }

}

在 web.xml 中:

<filter>
    <filter-name>disableSecureCookieFilter</filter-name>
    <filter-class>com.xxxx.security.DisableSecureCookieFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>disableSecureCookieFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

请记住,启用不安全的 cookie 会绕过重要的 https 安全性!(我必须这样做才能从 http 到 https 的平稳过渡)

于 2018-06-05T14:07:58.843 回答
2

我没有在 Tomcat 中找到解决方案,但如果你使用 apache 作为反向代理,你可以这样做:

Header edit* Set-Cookie "(JSESSIONID=.*)(; Secure)" "$1"

使用mod_headers它将在返回的途中删除标头以删除安全标志。不漂亮,但如果这很关键,则可以使用。

于 2017-02-08T18:05:03.407 回答
-1

除了上面 George Powell 针对 Apache 的解决方案,如果你在 IIS 上,你可以如下解决:

  1. 安装 IIS URL 重写模块
  2. 将以下内容添加到您的 web.config

<rewrite>
  <outboundRules>
    <rule name="RemoveSecureJessionID">
      <match serverVariable="RESPONSE_Set-Cookie" pattern="^(.*JSESSIONID.*)Secure;(.*)$" />
      <action type="Rewrite" value="{R:1}{R:2}" />
    </rule>
  </outboundRules>
</rewrite>

这个解决方案来自Pete Freitag 的博客

如上所述,自最近的 Chrome 更新(2017 年 1 月)以来,这已成为一个问题。

于 2017-02-20T23:41:07.483 回答