Hi all,

Summary:
--------

Just wanted to point out how to plug what appears to be a security flaw in
mod_ssl (although whether this flaw is readily exploitable or not would have to
be explained to us by some protocol expert ... Mr Rescorla, are you there?? :-)
I first mentioned this a while ago, but at the time I didn't really mention a
fix to anyone (because I didn't really bother looking into it) nor did I think
too hard about the possible consequences and seriousness of this issue.

Currently, mod_ssl uses OpenSSL's session-caching in the "standard" way. Ie. you
plug in callbacks if you want to implement a mod_ssl cache, and each httpd
process will invoke those callbacks during the normal caching operations (and
thus, different httpd processes will be able to resume each other's sessions if
the caching callbacks implement a cross-process cache, eg. "shmht", "shmcb", and
"dbm" in mod_ssl.

In its normal mode of operation, OpenSSL's caching code will keep a local cache
in each SSL context (there's "essentially" one of these in each httpd process).
So, when negotiating a new session with a client, the session will be added to
the local cache of that httpd process *and* mod_ssl's "add_session" callback
will install the session in the mod_ssl cache too. Then if you try to resume
that session, you'll probably hit a different httpd process[1] that will fail to
find that session in its local cache, but mod_ssl's "get_session" callback will
pluck it out of the mod_ssl session cache.

([1] turn "KeepAlive Off"!!!!! It's pure evilness that the damn thing still
exists.)

All good so far. You actually see this working; turn "ExtendedStatus On" and
enable the "server-status" handler (both are commented out but described in the
default "httpd.conf" file). Then use a web-browser to hit your server with the
"server-status" URL ... with either the "shmcb" or "shmht" caches (possibly
"dbm" too), you'll see the number of cache hits and misses listed at the bottom
of the status page. If you refresh the page a number of times - you should see
the number of "hits" go up corresponding to each time your request is handled by
a new process that you haven't spoken with before (it will reach into mod_ssl's
cache, score a "hit", and copy the session into its local cache). You will also
observe the potential problem;

Problem:
--------

Once you start being served by processes you've already communicated with
before, there will be no more cache hits or misses - each process has its own
copy of the session data cached and so doesn't bother asking the external cache
in mod_ssl.

SSL/TLS is not supposed to work this way w.r.t. session caching. In particular,
an unclean shutdown, and possibly other scenarios (renegotiations spring to
mind), are required to mark the session as invalidated - ie. it should never be
resumed by the server again. This might result from connection hijacking, or
some other trickery to launch a replay attack on someone else's SSL session.

Eg. If your web server is running 100 httpd processes, and process number 47
deletes a session for one of these reasons, it will be deleted from the local
cache of process 47 and in the mod_ssl cache too.  However, if the next request
that tries to resume that session (which should fail) hits any of the other 99
processes, the resume will *succeed* ... each of them has it cached locally and
doesn't even check with the mod_ssl cache. Ie. despite the fact a
"delete_session" callback is used to remove sessions that should *never* be
resumed by the server, there's a good chance any attempt to resume that session
*will* succeed anyway (where "good"==99% in our example).

Solution:
---------

So, the fix is to change mod_ssl to force OpenSSL to ignore process
local-caching and to always get/set/delete sessions using mod_ssl's callbacks.

The latest version of mod_ssl (2.8.4), at about line 604 of ssl_engine_init.c,
is where the cache options are set for OpenSSL when caching isn't completely
disabled. Ie.

    if (mc->nSessionCacheMode == SSL_SCMODE_NONE)
        SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
    else
-->     SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);

The "SSL_SESS_CACHE_SERVER" flag should be combined with
SSL_SESS_CACHE_NO_INTERNAL_LOOKUP. Ie.

    if (mc->nSessionCacheMode == SSL_SCMODE_NONE)
        SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
    else
        SSL_CTX_set_session_cache_mode(ctx,
            SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL_LOOKUP);

Feedback is welcome.

Regards,
Geoff

______________________________________________________________________
Apache Interface to OpenSSL (mod_ssl)                   www.modssl.org
User Support Mailing List                      [EMAIL PROTECTED]
Automated List Manager                            [EMAIL PROTECTED]

Reply via email to