5

The Play Framework for Scala has support for signed session cookies. In the application configuration file is an "application secret" that is set as a secure random number when the application source code is initialized. This secret is shared between multiple copies of the application running in a web server farm so that all cookie signatures can be checked on any server.

When a session is created in Play, the session is automatically signed using the application secret and HMAC-SHA1.

I am concerned that the same application secret is used for the life of the application. Is this concern valid?

I was trying to come up with a better way to sign the cookies, but I know the adage against inventing your own cryptographic techniques.

Is there some accepted way to have all of the servers share a changing secret?

I thought of the following (note that all session cookies are in-memory only and expire when the browser is closed):

  1. Embed the signature date (UTC) in each cookie.
  2. The signing key is randomly generated by the first signing of the day (after midnight) and stored in the database for all servers to share.
  3. When a server needs to sign a cookie, it checks its own signing key and the date it was generated and compares that date to the current date.
    • If the signing date is the same as the current date, the key is used to sign the cookie.
    • If the signing date is older than the current date, the server checks the database for a new signing key with the current date.
      • If there exists a key with the current date in the database, it is used for signing the new cookie. Old signing keys are retained (for some number of days) to verify older cookies.
      • If there is no key for the current date, a new one is generated (how do I handle multiple servers doing this at the same time in a NoSQL database?).

As an alternative algorithm, I can generate a new secret each day using HMAC(application secret, current date). With this, I do not need to store the daily secret keys in the database, since all servers can generate the same daily key sequence. I'm not sure if this is any more (or less) secure than storing the daily key in the database. I do need to protect the application secret, but no more so than I need to protect the database. It is recommended that the application secret not be stored in source control, but loaded from an environment variable set on each production server.

6

Insisting on frequent key renewal is an old tradition but is not mandatory. In older times, when cryptography was something for armies and spies, keys had to be renewed because spies were spied and soldiers were made prisoners in the course of their daily operations; it was thus unreasonable to believe that a secret value known to field agents could remain indefinitely secret. Thus came the habit of regular (and frequent) key renewals. This does not map well to Internet servers, for the following reasons:

  • Actual intrusions on your servers are rare events. The normal situation is that none occurs. You still want to use detection mechanisms, but you can expect that, on average, no intrusion occurs for months at a time.

  • When an intrusion occurs, the attacker enacts his main mischief immediately. This is a computer world; within the 10 seconds following the intrusion, the attacker has installed his rootkit, downloaded all the data which he is interested in, modified some records, and left. A daily renewal of keys will "kick him out" (i.e. make obsolete all fake cookies that the attacker could come up with using the stolen key) only long after the damage has been done. The key renewal dogma has been enshrined at a time when the average processing of data was a matter of days or weeks, not seconds. The time scale has changed a lot since these days.

Therefore I would say that a long-lived MAC key is not a crucial problem. Of course, you should mind all the details on how that key is generated, stored and shared between your servers; it is an important secret element with a high value for the attacker. However, renewal is mostly pointless, and can be dangerous, since it impacts the way the key is stored and shared. With a fixed, static key, you can store the key as an OS-protected file on each server, and shared with a one-time manual procedure under controlled conditions (e.g. before the servers are actually put online). If you want to renew keys automatically on a daily basis, then you will need some shared storage or network protocol, which inherently increases the exposure of that secret value. For instance, if you use some database scheme to generate and share the key-of-the-day, then the key can become an easy prey to a SQL injection attack, whereas a simple file would have remained confidential.

For these reasons, I recommend that you abstain from key renewal. It makes the problem much more complex to analyse, with higher exposure, for a gain which is, at best of times, highly questionable.

(Note: This "signature" is more correctly named a MAC. The term "signature" is, in cryptography, reserved for algorithms of the asymmetric persuasion, e.g. RSA, whereas HMAC is part of "symmetric cryptography", meaning here that the same key is used to generate the MAC value and to verify it.)

  • Thanks for the great explanation. That is probably the reason why Play was designed to use a single, unchanging, secret. – Ralph Dec 27 '13 at 15:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.