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  too.
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 time.
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, -- Brandon
1. https://forum.nginx.org/read.php?2,254881,254881#msg-254881 2. https://timtaubert.de/blog/2014/11/the-sad-state-of-server-side-tls-session-... 3. https://www.imperialviolet.org/2013/06/27/botchingpfs.html
Note that a solution for session ticket key rotation is actually trivial:
The second link contains some more info on the actual implementation and the relevant nginx parts.