Authentication and encryption keys in cookie based session management - session

My query comes from trying to use session store for eg. RedisStore in Golang where the store takes a vararg as last argument which as per document are pairs of authentication and encryption keys.
Most of the examples I see just use a single argument here (for eg. "secret", "mysecret" etc.) and I couldn't get any information about what is achieved by sending multiple pairs of authentication and encryption keys.
Could someone please explain more or direct me to some information about the purpose of the authentication and encryption keys in session management using cookies.

From the docs:
Keys are defined in pairs to allow key rotation, but the common case is to set a single authentication key and optionally an encryption key.
The first pair is used for authentication, encryption and decryption, all other pairs are only used for authentication and decryption (but not encryption).
This is a very common strategy for key rotation. A new key pair is generated regularly and becomes the new key for encryption. Some or all other keys are kept around so that existing data can still be decrypted for some time. The oldest key can be discarded eventually. This limits the impact of a disclosed key because it becomes useless after some time.
Other software that uses this method:
Google's KMS: https://cloud.google.com/kms/docs/key-rotation
Amazon's KMS: https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html
HashiCorp's Vault: https://www.vaultproject.io/api/secret/transit/index.html#rotate-key

Related

What is the purpose of nonce and hmac in a session cookie?

I am looking at some code, and they are storing a "nonce" and a "hmac" in a users session cookie. What is the purpose of a nonce? What is the purpose of the hmac?
The HMAC (Hash-based Message Authentication Code) is a cryptographic Hash of the actual data of the cookie. So that the server can verify the data hasn’t been tampered with.
The Nonce (Number used once) is most likely used to encrypt the data of the cookie. Usually, when you encrypt something, you don’t want the ciphertext to be the same for identical plain messages. So you use the static encryption key in conjunction with a random Nonce changing on every encryption.

Password security in sessions

Instead of stroing plain text passwords, we use a strong hashing function with high computation cost and random salt to thwart rainbow attacks etc.
But when a user is in a session, typically his or her username is stored along with a hash of their password as a cookie to authenticate the sesssion. If the user's browser cookie space is compromised, doesn't an attacker obtain an easier target of cracking the username+ session hash, instead of username + pass hash?
In Django for example, passwords are hashed with PBKDF2 or bcrypt, but session hashes use a less complex HMAC and no random salt. Is this a security issue? If yes, what is the right way to handle sessions?
For each session, I suggest to use dedicated SessionID - random long 128bit value. And, keep session key as:
username:SessionID:hash
where
hash = sha1(SessionID|username|client_IP|secret_server_side_password);
Every time, when you receive cookie, you need again compute hash, and compare with received one.
As result, this cookie is useless after session is closed (mismatch SessionID).
Moreover, if cookie will be stolen from active session, server can
figure out attack with stolen cookie from another computer, because of client_IP from real client will be different to actual client_IP.
Of course, if ClientIP is changed, session automatically will be disconnected.
Alternative - using authentication system, based on client's
SSL certificates, for example - emcSSL.

ajax login procedure - is using salt and hash is really neccessary?

I'm sending password that user inputs to the server without obscuring it. I've read some suggestions to do the following before sending the data:
Ask the server for a seed value (a salt) using an ajax request
Hash the password + seed using a sha1 sum
Are these steps really enforce security in any substantial way? The salt isn't going to be unique so everyone can get it. The algorith of applying the salt is available to everyone as it is applied on a client. The algorithm of sha1 sum is also available so anyone can use it to unhash the password. So what's the benefit?
As far as I know these steps (Digest auth) the salt is unique for every session, so every login attempt will get its own, different salt. Please consult your sources if it is the case there, too.
The client, after reading the salt for the current login process and sends the hash of the password+salt to the server wich compares it to its own hash of password+salt.

How does perfect forward secrecy (PFS) work

I'm in an infosec class and I stumbled upon this concept online and it intrigued me. I've also looked at a few websites and wikipedia that explain the concept, as well as a few posts on stackoverflow, but I'm still getting confused. From what I understand is in a typical HTTPS public key exchange, a browser and a server come together with keys to create a session key...if someone ever obtained a private key that derived the session key, they could see all the data that was sent between this connection, even in the past.
My understanding is that with PFS, the 'session key' is never sent , even in encrypted form. It is kept secret so that even if someone found a private key, they wouldn't be able to access encrypted recorded information from the past. Is this correct?
I also was wondering, If I am partaking in a PFS exchange call me "A", with a server "B", PFS is supposed to work with the fact that if my key becomes compromised, A and B's conversation wont become compromised because they don't know the session key. But how does "B" authenticate me as "A", if my key has in fact became compromised...e.g. how would it know the difference between me (A) or another user (C) using my key attempting to access the data.
I really like the answer on Quora given by Robert Love: http://www.quora.com/What-is-perfect-forward-secrecy-PFS-as-used-in-SSL
Let's look at how key exchange works in the common non-ephemeral case.
Instead of giving a practical example using, say, Diffie-Hellman, I'll
give a generalized example where the math is simple:
Alice (client) wants to talk to Bob (server).
Bob has a private key X and a public key Y. X is secret, Y is public.
Alice generates a large, random integer M.
Alice encrypts M using Y and sends Y(M) to Bob.
Bob decrypts Y(M) using X, yielding M.
Both Alice and Bob now have M and use it as the key to whatever cipher they agreed to use for the SSL session—for example, AES.
Pretty simple, right? The problem, of course, is that if anyone ever finds out X, every single communication is compromised: X lets an attacker decrypt Y(M), yielding M. Let's look at the PFS version of this scenario:
Alice (client) wants to talk to Bob (server).
Bob generates a new set of public and private keys, Y' and X'.
Bob sends Y' to Alice.
Alice generates a large, random integer M.
Alice encrypts M using Y' and sends Y'(M) to Bob.
Bob decrypts Y'(M) using X', yielding M.
Both Alice and Bob now have M and use it as the key to whatever cipher they agreed to use for the SSL session—for example, AES.
(X and Y are still used to validate identity; I'm leaving that out.)
In this second example, X isn't used to create the shared secret, so even if X becomes compromised, M is undiscoverable. But you've just pushed the problem to X', you might say. What if X' becomes known? But that's the genius, I say. Assuming X' is never reused and never stored, the only way to obtain X' is if the adversary has access to the host's memory at the time of the communication. If your adversary has such physical access, then encryption of any sort isn't going to do you any good. Moreover, even if X' were somehow compromised, it would only reveal this particular communication.
That's PFS.
In a non-PFS session the browser decides on the session key (or rather secret from which it is derived) and encrypts it using RSA, with the RSA public key obtained from a certificate that belongs to the server. The certificate is also used to authenticate the server. The server then uses its private key (what you call master key) to decrypt the session key.
All connections to the server use different session keys, but if you possess the master key you can figure them all out, the way the server does.
In PFS you use algorithms such as Diffie-Hellman, where the master key is not used. In such connection the master key is used to authenticate the parameters for the algorithm. After the parameters are agreed on, the key exchange takes place using those parameters, and a secret of both parties. The parameters are not secret, and the secrets the parties used are discarder after the session key is established (ephemeral). This way if you discover the master key you cant discover the session key. However you can pose as the server if you get the key, and the certificate is not invalidated.
To find out more read about Diffie-Hellman.
You generate a new public key for every message, and use the real permanent public key only for authentication
This was mentioned in other answers, but I just want to give a more brain parseable and contextual version of it.
There are two things you can do with someone's public key:
verify that a message was written by them, AKA verify a message signature AKA authenticate a message. This is needed to prevent a man in the middle attack.
encrypt a message that only they can decrypt
In many ways, authentication is the more critical/costly step, because to know that a given public key belongs to someone while avoiding a man in the middle attack, you need to take steps such as:
meet them in real life and share the public key (leave your home???)
talk to them over video (deepfakes???)
trusted signature providers (centralization!!!)
Generating new keys is however comparatively cheap.
So once you have done this costly initial key validation step, you can now just:
ask the receiver to generate a new temporary public key for every message you want to send them
the receiver sends you the temporary public key back to you, signed by their permanent public key. Nothing ever gets encrypted by the permanent key, only signed. No need to encrypt public keys being sent!
you verify the message signature with the permanent public key to avoid MITM, and you then use that temporary key encrypt your message
After the message is received and read, they then immediately delete that temporary private key and the decrypted message.
So now if their computer gets hacked and the permanent private key leaks, none of the old encrypted messages that the attacker captured over the wire can be decrypted, because the temporary key was used to encrypt them, and that has been long since deleted.
Future messages would be susceptible to MITM however if they don't notice and change their permanent key after the leak.

With a session store on the server, what does session secret do?

I understand if one saves sessions to cookies, you need to encrypt them with a secret else malicious clients could modify their session at will. This design is still bad for many reasons popularly discussed.
However, if one saves sessions on the server (I happen to use a Memcache store via Rack:Session:Dalli) , I understand all the client gets is a cookie with a key the server uses to lookup their session from the store. I still set a session secret. But I don't understand what it does anymore.
Encrypting a large random number results in essentially another large random number. In other words, if there is no meaning ascribed to the information (its just a random number), then there is no security benefit to encryption. If the ID you're storing has some information embedded in it, like a certain bit set or only a certain subset of IDs are used, then encryption is useful.
The length of the session ID is important. Obviously, the longer the ID, the more resistant it is to brute forcing. The expected number of simultaneous user sessions is also a factor, as the number of sessions reduces the number of brute force attempts needed to find a valid session ID. For example, two simultaneous sessions reduces the effective strength of the ID by one bit (a 128 bit key becomes as effective as a 127 bit key would be with one session only). An Amazon-scale website with (say) 1,000,000 simultaneous sessions would effectively lose 20 bits of its session key strength.
If you need to defend against brute force attacks, implement a middleware to check for that. Adding information to the session id, like an application-unique string, can make detecting a brute-force attack easier (and requires session id encryption). Note that this does not enhance the security of the key itself, and is basically wasted effort unless the app takes some action when presented with an improper session id.
Whatever you do, just make sure to use SSL and set the cookie to https only. Time out the session server-side, and don't rely on cookie expiration and the good will of the client browser.
TL;DR: If only using cookies for session ID storage, encryption is not necessary if a good RNG is used. Use SSL and set the cookie secure attribute.

Resources