Tomcat中session的安全问题


本文是基于apache-tomcat-7.0.54。

阅读了创建session的源码,发现有极小的可能性,session会被覆盖(不安全)。 下面从ManagerBase的createSession方法开始

@Override
public Session createSession(String sessionId) {
    if ((maxActiveSessions >= 0) &&
            (getActiveSessions() >= maxActiveSessions)) {
        rejectedSessions++;
        throw new TooManyActiveSessionsException(
                sm.getString("managerBase.createSession.ise"),
                maxActiveSessions);
    }
    // Recycle or create a Session instance
    Session session = createEmptySession();
    // Initialize the properties of the new session and return it
    session.setNew(true);
    session.setValid(true);
    session.setCreationTime(System.currentTimeMillis());
    session.setMaxInactiveInterval(this.maxInactiveInterval);
    String id = sessionId;
    if (id == null) {
        id = generateSessionId();
    }
    session.setId(id);
    sessionCounter++;
    SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
    synchronized (sessionCreationTiming) {
        sessionCreationTiming.add(timing);
        sessionCreationTiming.poll();
    }
    return (session);

}

generateSessionId方法
protected String generateSessionId() {
    String result = null;
    do {
        if (result != null) {
            // Not thread-safe but if one of multiple increments is lost
            // that is not a big deal since the fact that there was any
            // duplicate is a much bigger issue.
            duplicates++;
        }
        result = sessionIdGenerator.generateSessionId();
    } while (sessions.containsKey(result));
    return result;
}
创建sessionId时会判断sessions(sessions是ConcurrentHashMap)中是否存在,若存在则一直循环,直到唯一。 新创建的session是session.setId(id)写入的。

假设这样一种情况,通过generateSessionId得到了第一个sessionIdA,这时还没有session.setId(sessionIdA), generateSessionId又创建了一个sessionIdB,恰巧sessionIdA=sessionIdB(这种几率非常低),这种情况下,前一个session就会被后一个session覆盖。

我们在SessionIdGenerator中写个main方法,测试下是否会出现sessionId重复的情况。

public static void main(String[] args) {
    SessionIdGenerator generator = new SessionIdGenerator();
    generator.setSessionIdLength(5);
    Map map = new HashMap();
    for(int i=0; i< 100000000; i++) {
        String key = generator.generateSessionId();
        if(map.containsKey(key)) {
            System.out.println("i= " + i + "  " + key);
            break;
        }
        map.put(key, null);
    }
}
sessionIdLength默认值为16,这种情况下,很难重复。于是我改为了5,在有限时间内重复一般都会出现。

结论:tomcat的session在极小概率的情况下会有问题。

若分析有误,希望提出来,谢谢。


上篇: First Blog 下篇: 折腾的GAE-BBS