ssl_session_timeout and forward secrecy concerns
bblack at wikimedia.org
Thu Jun 9 16:40:19 UTC 2016
This topic has been brought up before here on the forums with no response .
The blog post linked there from Tim Taubert  suggests that entries
in an ssl_session_cache (and let's presume the common case here that
it's a shm cache) don't get explicitly purged on expiry. It seems to
be backed up by some text from the related post by Adam Langley 
Therefore, the argument goes: because a large cache (relative to
session rate) could hang onto a cached expired session in memory for a
very long time, an administrator who cares about forward secrecy in
the face of server breach needs to mitigate by periodically wiping the
whole cache (nginx restart) and/or setting the size relatively-small
to ensure the entire cache will be fully-overwritten in reasonable
While tuning and playing with related things, I got curious about how
hard it would be to add explicit purging of expired sessions from the
cache, so that we could size caches with large headroom and not have
to worry about the forward-secrecy implications. Once I started
looking at the code, it seemed to me like sessions are already
actively purged via two separate mechanisms:
A) In the nginx code itself, in ngx_ssl_new_session(), there's an
explicit unconditional call near the top that drops up to 2 expired
sessions from the expire_queue, if there are any actually-expired
ones. This is separate from and before "expiring" the oldest
unexpired sessions just to make room in the cache if necessary.
This seems to provide a fairly reasonable path for expired sessions
getting regularly purged if the overall session rate is
relatively-stable, but might leave them longer than expected if the
new-session rate drops off significantly from past highs.
B) In OpenSSL, the default is apparently to purge *all* expired
sessions periodically (every 256th received connection). There's an
option to disable that behavior ( SSL_SESS_CACHE_NO_AUTO_CLEAR ), but
nginx doesn't set that option when a shm cache is configured.
The OpenSSL-level flushing code used here seems to zero out the secret
data, and also invokes the session remove callback set up by nginx to
clear it from nginx's rbtree and such. I would think this alone would
solve the problem even without the stuff in ngx_ssl_new_session(),
assuming you can guarantee a bare minimum new-session rate of 256/day
or so (easy: if nothing else create a curl cronjob to ping your server
in case of zero legit traffic flow).
Perhaps I'm reading the code wrong, or I've made some faulty
assumptions about how it works?
Or are these blog posts actually wrong and nginx's ssl_session_timeout
is already a safe boundary for forward secrecy issues all on its own,
assuming the 1/256 flush built into openssl is regularly triggered?
Thanks for any insight,
More information about the nginx-devel