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.
Related
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.
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
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.
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.
I was told that it was easy but people to view the contents inside the $_POST[] array, is it really that easy? How do hackers do this and how do I prevent it? Should I start storing more items in the SESSION[] array instead?
POST[]ing Extra Values
The POST array is populated entirely by data transmitted from the client and everything inside it should be suspect. So don't take a number out of a postback request and set someone's account balance to it.
Also, "POST" is just a type of HTTP request, which means it's sent in plain text. Don't ask clients to send you login passwords over POST unless you wrap the HTTP stream with SSL (use https:// and configure your webserver properly) because you don't control the network between the client and your server. Major websites often don't do this (for performance reasons) but all online banks have done this for at least 10 years.
Think that POST data are sended from the browser with the HTTP request in plain text.
People that can snif your network or execute a Man in the Midle hack, can view this.
With a firefox extension like Tamper Data, the user can change the POST data before sending it to the server.
Never thrust POST data, always validate it in the server side.
From my comment on your earlier question:
A hacker can see the fields and values that are submitted through your form using easily available software tools, and then re POST them as he/she wishes.
Regarding MD5:
md5 isn't an encryption algorithm, it's a hashing algorithm. It'll turn any string into a 16-byte hash. In theory:
If you have two objects, a and b, and md5(a) == md5(b), then a == b
If you have md5(a) you can't figure out a.
These are the implicit assumptions when working with hashes, although they're never actually true - number one is clearly not true because if you hash 2^16 + 1 different strings then by the Pigeonhole Principle there must be two different strings with the same hash. The second one is also obviously not true because an attacker can search the range of md5 values for the hash, although for modern cryptographic-secure hashes (not md5) this is infeasible.
Getting to your question, you could just ask the client for the md5 hash of the user's password (you'd need client side javascript to calculate this) but that's a terrible idea. If all you expect from the user is the md5 of her password, then that's all an attacker needs to know, and you're sending it in plain text. What you could do is send the client a nonce. This is like a challenge. For the client to prove she knows her password, she can send you a hash of the nonce and her password concatenated. The idea is that any attacker can't answer the challenge becuase he only knows the nonce, and after the nonce-password hash is transmitted it's too late for him because you've already received it and aren't expecting an answer to that nonce again. Property 2 ensures that he can't extract the password from the hash.
This is vulnerable to the attacker stealing the challenge response and getting it to you before the client does. You can have a lot of fun making up a whole cryptosystem with multi-round communication (counter-intuitively it's actually possible to send hashes back and forth and securely authenticate) but soon you're just implementing HTTPS which someone else has already done for you :)