HTTP Remember me authentication - security

I'm trying to write a simple HTTP remember me authentication system for users.
My users could be represented as such
{
"email" : "foo#bar.com",
"password" : "8EC41F4334C1B9615F930270A4F8BBC2F5A2FCD3" // sha1 hash of password
}
So my idea is that I need to create a cookie, with indefinite (really long) expiration time, that will hold some type of information to enable me to fetch the user from the database, therefore logging the user in.
My first idea was to just simply store the email:password string as a cookie. I thought this would be good since nobody else can really generate that type of information other than the user itself, and I could retrieve the user quite easily by simply comparing the username and password based on what's in the database.
However then I thought this wasn't really good. It turns the password digest into, effectively, a second password that's stored in the clear and passed over the wire in every request.
So then I thought maybe I could generate a signature each time the user logs in, which would basically be a random hash that is stored directly in the user object in the database.
The user logs in, it generates this signature that is stored, and the cookie holds this signature. Whenever you access the website, the site checks which user has that particular signature and logs the user in. Logging out will effectively erase the cookie, and new logins will generate a new random signature.
Does this approach take into account any other vulnerabilities?
I know, I should probably use a library already made for this, but this is just simply an exercise in web-security.

This is essentially what most sites do when you log in. Yes, the cookie should hold a unique identifier for the user's "session". The cookie should be essentially random. Up to you whether to make it persistent across browser sessions.
Along with the cookie in your authentication DB, also store a timestamp of when the entry was created. Cookies older than N seconds should be considered invalid (set N to your taste). You can reset the timestamp each time the cookie is used so that idle sessions time out.
Note that the same user may want to have multiple sessions (do you ever log in to your Email account from both home and work?), so the concept here really is "session", not user.

Vulnerability point-of-view both are same! Cookie stealing and related mechanisms however browsers are smart enough now so you shouldn't worry about that.
Second approach is good in terms of privacy as well since it does not includes email address in the cookie. And it seems much more similar to like storing the sessionID which in your case you are generating a random hash and storing it in DB.
But i think it would be more wiser to use the first approach; you can add another layer to the digest and encrypt it with your some algo or private key; to be on safer side.

Related

Should session ID cookie be signed?

I was using the Node library https://github.com/expressjs/session and noticed that it requires a secret to be specified for signing the session ID cookie.
If just the session ID is being stored in the cookie, and not any data, what is the use in signing the cookie?
My reasoning is that if someone wanted to modify a session ID cookie, then that's fine if the session ID sufficiently long to prevent brute force attacks. Am I missing something?
I questioned this as well and the only answers I could think of were,
a) If someone (for no good reason?) changes the default session ID
generation to a non-cryptographically random session ID, signing it
helps prevent attackers generating valid session IDs.
b) Reduce round trips to the session store by validating the session
ID using the signature/HMAC. (I can only imagine this being a problem
for DoS attacks).
Both seem like valid reasons though using good session caching would negate the need for b) and assuming your library's users are daft enough to change the default session ID generation, it seems a bit much to safe-guard against their own stupidity when the majority of users would just use the default generation algorithm.
If you store just id of session there is not reason to encrypt it. You are right.
You need to encrypt if you store some session data inside cookie, not only id.
This will prevent users of changing session data.
A session_id cookie is anything (number or alphanumeric) which identifies a client to a server, which in turns stores (usually temporary) data on the server accessed through this session_id/key.
The point is, if the cookie is going to be passed forth and back over HTTP, it doesn't matter whether you have "signed" it or not. Any man-in-the-middle could get your "signed/encrypted session_id" and make further requests pretending be the proper user. And I mean, this attacker doesn't have to care which information is inside the encrypted data, he could pass the exactly same signed/encrypted data, and the server couldn't figure out if it comes really from the right user.
In cases like these, you have to figure out if the privacy is important, if so, don't think too much, you got have to use HTTPS. If you understand it is not so important, don't waste your "processing time" signing/encrypting and decrypting your session id.
This answer is valid only for signed session_id.
I believe the reason it is signed is so that it is not easily guessable. For instance if someone decided to use integers as session id's, you could easily impersonate another user's session by trying multiple numbers. I believe that the signing makes it so that changing your session id value client side will not be valid (that is it prevents tampering).

How to remember users with cookies in a secure way?

So lets say i have a member base website and when the user signs in i put put a cookie (or a session) with a key value pair remembering who the user is. But its just come to my attention which information i should use to remember the user so that its secure. I cant use username=username or user_id = user_id (because my user_id will be 1), because people then can just simply guess what the cookie values are and logged in as that user. So what key/value pair should i use to be able to identify users and still connect their information to the database securely? Thanks.
Ben, there are a few different types of attacks you need to be concerned with. For example simply encrypting the identifier with a private key doesn't prevent someone who can intercept the encrypted value from simply replaying it to your server (and appear to be the user). Some common security risks are detailed here (and in associated links at bottom of this page):
https://www.owasp.org/index.php/Session_hijacking_attack
Session management can be quite complex and depending on the level of security you require, it is not something you want to tackle yourself, because likely your development environment / framework already has a solution that has been vetted moreso than a homebrew solution. Here is a link detailing some things to consider, unfortunately this topic has more to it than a simple Stack Overflow post:
https://www.owasp.org/index.php/Session_Management
If you dont prefer encryption for whatever reason, then a simpler solution could be to use a GUID to identify the user. This way, a hacker would have to launch a denial of service kind-of attack on your application to be able to run through even a very small fraction of the GUIDs.
If you want to do this properly, then you should have a look at http://jaspan.com/improved_persistent_login_cookie_best_practice also.
I'm definitely not an expert in security, but I have recently implemented user management tool and I have done the following.
Don't use encryption, its slow and most of the time for simple implementation its just a waste of time.
Here is what you do need to store on the server - in order to authenticate each request.
UserId (obvious)
CookieHash (made out of userId, some secret private key and crypto randomly generated number)
LastLogin
SessionRenewed (useful for when to cancel someone's session eg. renew cookieHash every 10 min, otherwise log out user)
LastIP
What I store in cookie is following
UserId
CookieHash
How to use this basic security
Simply when user logs in you check username/password etc. (just the usual) If everything is fine then log in user and generate new cookiehash and fill those values given above.
Every request check UserId against its hash. If someone gave UserId = 4 but hash didnt match then automatically drop a session and forward user to login screen. Possible log is good to see how often people try to play around with your hard work.
I hope this helps.
You can just encrypt the user id with a private encryption key that you keep on the server. There are a few things to watch out for with this approach:
Every call to the server will require you to decrypt the cookie to get the id of the user. This will add overhead to each request.
If the key is ever compromised, you will be forced to abandon the current name for the cookie you use and use another encryption key when assigning to the new cookie name; this will cause the user to have to re-login, of course.
While I don't think that these are major hurdles, they might be to you, and you would have to evaluate the impact on your site for yourself.

Is it advisable to store a hashed password in a cookie?

I want user's to be able to select a "remember me" box on my website so they need not log in each time they come. So, I need to store a unique ID in a cookie to identify them. Is it safe to hash their password with sha512 and a long salt in PHP and store that value in the cookie?
If the cookie was stolen, would their password be at risk?
Obviously it must be connected to their password somehow, otherwise if the cookie value was guessed or stolen, the user would not be able to stop someone else logging in.
Also, is it advisable to use a GUID at all as the unique identifier?
Thanks,
Ben
Remember, the hash of the password is effectively the same as their password. Somebody who stole the hash would have the same access to the user's account as if they had stolen their password. Therefore it is not advisable to store a hash of the user's password in a cookie unless there was some other information not stored with the cookie that is used to authenticate (i.e. 2-factor authentication).
Here is an excellent article on this very topic. Many of the answers to your question are hitting on techniques outlined in it.
There's a low risk with a good algorithm and large salt, but why take any unnecessary risk?
If you just need to identify the user, then store something that can uniquely identify the user, like a guid along with some other stored verification code (not their password, some random long string). I wouldn't use a guid alone as it would not be a safe method of authentication.
It wouldn't hurt to have some kind of "password" in the cookie along with a user id (to prevent users from changing the uid to that of another user), just don't make the "password" the same as the actual user's password.
And just because it's a hash doesn't necessarily mean it's one-way (well, by definition it does, but there are utilities to generate MD5 plaintexts and I would guess it's only a matter of time before it happens to others). I would hash some kind of secondary password.
An alternative way of doing this might be use the cookie as an encrypted storage for only indirection data. You'd need some sort of unencrypted identifier that would serve as a pointer to the key (or the required information to derive the key) in the application's database, followed by a blob encrypted by the key obtained from the identifier, which itself would contain some sort of one-time-usable identifier that authenticates the session.
Given the following assumptions:
Your database is secure (e.g., your application can access it, but your user cannot directly do so, and also assuming that the application has been proofed against SQL injection)
Your salts are strong; that is, reasonably high-entropy enough that attempting to crack the salted password is infeasible even if the password is known
Then what this would provide is a method by which one can be reasonably certain that the session is not able to be hijacked or stolen in any way. That is to say that a copied cookie is only of limited usefulness, since the user must not have used the cookie between its theft and usage by an attacker.
While this protects against replay, it also means that if someone does manage to steal the cookie at exactly the right time, and manages also to use it before the original, legitimate user does, the attacker now is in control of the session. One can limit a session to an IP address to mitigate that risk (somewhat; if both the user and the attacker are behind the same NAT, which is the most likely scenario in any home or small-to-medium business network) then this point is pretty moot, since the IP address would appear to be the same anyway. Also useful might be limiting to the current user agent (though that can break unexpectedly if the user updates their browser and the session does not expire at browser close time), or finding some method by which one can identify the computer that the user is on just well enough that there is reasonable certainty that the user hasn't moved the cookie from one system to the next. Short of using some binary plugin (Flash, or Silver/Moonlight), I'm not sure that the latter is possible.
To protect against a permanent session hijacking, require that the user to reauthenticate him- or herself periodically (e.g., limit the allowed session lifetime or require something like a token/fob/dongle) and require that the user reauthenticates him- or herself upon entering sensitive areas of the application, such as password change and potentially dangerous actions, patterns or behaviors such as the deletion of data, unusual usage patterns, bulk actions, and so forth.
It is difficult to secure applications and yet retain their ease-of-use. If done carefully, security can be implemented in a manner which is minimally intrusive and yet still effective—well, for most Internet-facing applications, anyway.
It's not advisable, but if your gonna do it, at least salt your passwords before you do so. This will stop people from using hash crackers if they do manage to get hold of your visitor's cookies.

Is it safe to store user object in a cookie?

I have a user object which contains information about the user (username, ip, country, name, email... but NOT password).
Should I store just the username in the cookie and then retrieve all info from DB upon loading the page, or just store the entire User object in the cookie?
You can't trust any information stored in a cookie, as the user can manipulate it at his/her leisure.
I suggest using a PHP session to store the object. That way, the end user only has a session ID stored in a cookie, with the real data on your server.
The session will eventually time out, though... forcing the user to log in again.
Edit: Whoops, I should point out that sessions are really easy to use. Just do the following:
session_start(); // This MUST be at the very top of every page that accesses the session
// Store something in the session with the key 'something'
$_SESSION['something'] = "Hi, I'm a session!";
// Retrieve 'something' from the session
$myString = $_SESSION['something'];
The standard rule of 'never trust posted data' applies to cookies too. I suggest storing just the user ID as well as a hash of the ID and some secret known only to the server.
For that case, I'd say store the user-id in the cookie and that's it. Then, upon first load of the page you load everything you need from the database and go on using a session as long as the user stays on your page.
To test if the page is loaded the first time, I just set a bool in the session if it has been loaded. If the bool doesn't exist, your user loads it initially.
There are probably better ways of doing this, but it works nice and easy. :)
Only store a session id! Never meaningful data such as user id. Imagine that you have a site with 10,000 users. Chances are that you have at least one user called superman and batman - if yous tore a username in a cookie to access your session information - it is potentially feasible for me to manipulate that cookie to change stored info from my username to batman and gain access to batman's account if his session is still alive. If you store some sort of randomly generated session id - it's pretty much impossible for me to figure out a session number that would work for another user to hijack that session.
You can trust information in the cookie if you use something like Hmac. Users could still see the data, but you would know if they had tampered with it (for example, changing their username to someone's else's in an attempt to see another user's data). If you don't want them to see the data, you could also symettrically encrypt the data you're sending. Obviously there's a CPU overhead to all of this, and a bandwidth overhead the more stuff you cram in there, but it's entirely legitimate to do what you're asking.
You can't assume the username being passed from a cookie is the actual username you wrote to the cookie. That is why they suggested using the sessionID. Using the sessionID you can go get the username and like he said is only good for 20 minutes or whatever you set your session timeout to be. SessionID doesn't reveal any private data. I had your same thought before I found this post though.

CSRF protection by storing nonce in Session variable and form

To protect against CSRF you should put a nonce in a hidden field in the form, and in a cookie or in the session variable. But what if the user opens several pages in different tabs? In this case each tab would have a form with a unique nonce, but there would be only one nonce stored in the session variable or cookie. Or if you try to store all the nonces in the cookie/session variable, how would you identify which one belongs to which form?
You can store the same nonce in each of the forms. The easiest way to do it is to tie the nonce to the session ID, so that those forms only work in that session.
You will want to make it hard for attackers to snarf session IDs and create their own nonces. So, one way to go about it is to use HMAC-SHA256 (or the like) to hash the session ID, using a key that you do not expose to the public.
(Obviously if the attacker can get the actual session ID itself, they can already do session hijacking. So that's not what I'm talking about, but rather the ability for an attacker to craft a script (that runs on the victim's computer) that can somehow grab the session ID and use that to dynamically generate a URL with the nonce pre-filled.)
ETA: Whether the above approach is enough on its own depends on how long you expect your typical sessions to last. If users usually use long-lasting sessions spanning longer than a few hours, you'll need to use something more sophisticated.
One approach is to create a new nonce for each form, that contains the timestamp, as well as hash(timestamp . sessionid) (where hash is some variant of HMAC as described above, to prevent forgery, and . is string concatenation). You then verify the nonce by:
checking the timestamp to ensure that the nonce is fresh enough (this is up to your policy, but a few hours is typical)
then, calculating the hash based on the timestamp and session ID, and comparing against the nonce, to verify that the nonce is authentic
If the nonce check fails, you'll want to display a new form, pre-populated with the user's submission (so that if they took a whole day to write their post, they won't lose all their hard work), as well as a fresh nonce. Then the user can resubmit straight away successfully.
Some people do generate a token for each form, and that is a very secure approach. However, this can break your app and piss off users. To prevent all XSRF against your site you just need unique 1 token variable per session and then the attacker will not be able to forge any request unless he can find this 1 token. The minor issue with this approach is that the attacker could brute force this token as long as the victim is visiting a website the attacker controls. HOWEVER if the token is pretty large like 32 bytes or so, then it would take many years to brute force, and the http session should expire long before then.
What you're describing is not a nonce anymore (nonce = number used once), it's just a session identifier. The whole point of a nonce is that it is only valid for a single form submission, therefore offers greater security against hijacking than just a session ID, but at the cost of not being able to have multiple tabs operating in parallel on the site.
Nonces are overkill for many purposes. If you use them, you should only set and require them on forms that make critical changes to the system, and educate users that they cannot expect to use more than one such form in parallel. Pages which do not set a nonce should take care not to clear any previously stored nonce from the session, so that users can still use non-nonced pages in parallel with a nonced form.
Long time back this post was written.
I've implemented a csrf blocker that I'm almost certain protects well.
It does function with multiple open windows, but I'm still assessing the kind of protection it offers. It uses a DB approach, ie storing instead of session to a table.
NOTE: I use MD5 in this case as an easy anti-sqli mechanism
Pseudo Code:
FORM:
token = randomstring #to be used in form hidden input
db->insert into csrf (token, user_id) values (md5(token),md5(cookie(user_id))
-- the token is then kept in the db till it's accessed from the action script, below:
ACTION SCRIPT:
if md5(post(token)) belongs to md5(cookie(user_id))
#discard the token
db -> delete from csrf where token=md5(post(token)) and user_id=md5(cookie(user_id))
do the rest of the stuff

Resources