Is it secure if I store a sha1 password and a userID in secure flag & https Cookies? - security

I'm doing a connection system for my users. So I decided to use Cookies to store the User ID and the password (in sha1). But I have one question. If a random user gets the value of both cookies and their names, can he creates them with for example a js function and get into the account?

Is it secure if I store a sha1 password and a userID in secure flag &
https Cookies?
No.
I suppose you want to know why? First, define "safe." What threat are you trying to mitigate?
Once the credentials are hashed, there's no way to get the plaintext back. Since you can't render the hashed string back to plaintext then we can assume that the intent is to compare them to the same hashed string held at the server, yes? That's awesome if the threat you want to mitigate is somebody discovering the password and user ID and you use something like SHA256 instead of SHA1.
But if the threats you want to mitigate include replay attack or session hijacking, then these are no better than any other fixed string. In fact they are worse. If the user is obliged to provide their password for each HTTPS request it sucks for them but at least the app can throttle login attempts and foil a brute force attack. If the credentials are hashed and exchanged in cookies, then they are exposed to adversaries and if obtained can be subjected to brute force cracking or looked up in a rainbow table so on net sending the credentials back out, even encrypted or hashed, kinda sucks.
The question doesn't mention salt or session keying. An adversary will look at the cookies to see identical values are returned over multiple sessions. To prevent replay attack you'd need to append a nonce before hashing to act as a salt so the hashed string changes each time. But it doesn't solve the problem of sending a transformed credential pair outside of control of your own server or that this is far worse than just using a long random string for the same purpose.
Furthermore, the hash of the credentials doesn't time out until and unless the user changes their password - at which point it tells an adversary that the user just changed their password which is a great piece of info with which to social engineer the IT support person who does password recovery. "Hi, I just changed my password and locked the account. Can you reset it? Employee ID? Well if I had access I could look it up. Can you just reset it? I'm really me. How else would anyone I know I just changed it?"
The support person would never guess the answer to that question is "because Victor's app design told me it was just changed" and might just reset it for the adversary. But if the session is kept alive by a session cookie or a triparte login token then the unique string representing that user's session mitigates all of the threats discussed so far:
An attacker can't reverse it or crack it to discover credentials because they aren't in there.
It can't be used for session replay since it is generated to be unique for each session.
It expires within a short period of time so it can't be resurrected from browser cache or history.
But rather than answer the question as asked, I'd like to answer the question "Is there an authoritative source for comprehensive web application security best practices?" That's a much easier question to answer and it potentially answers your initial question if you follow through with the required study.
Please see: Open Web Application Security Project (OWASP).
In particular, please see the Session Management Cheat Sheet and the Authentication Management Cheat Sheet as these cover much of what you are trying to do here.
OWASP periodically analyzes all reported breaches for a recent period and then publishes the Top 10 Vulnerability List based on the root causes that showed up most often during the sample period. When I QA new web sites on behalf of clients they almost always have several of the defects in OWASP's Top 10 list. If as a developer or web site development company you want to stand head and shoulders above the crowd and get a lot of repeat business, all you need to do is make sure the site you deliver doesn't have any defects in OWASP's list. The question suggests any application built as proposed would have at least 4 or 5 defects from the OWASP Top 10 so that's an aspirational goal for now. Aim high.

Related

Is username and password in HTTPS URL secure?

I am sending POST request to URL https://username:password#example.com in my script. I know that HTTPS encrypts credentials so they should not be visible on network.
But what about server logs, will they be visible there?
Are there any other disadvantages of using this approach?
How can I make authentication more secure on client/server side?
You can find more information here: Are HTTPS URLs encrypted? (tl;dr: the way you are sending it is not encrypted most probably, but you can send the credentials as URL parameters instead, to make it encrypted).
Next, if you have developed the server/are in control, it is up to you to decide whether to keep logs or not. If you are unsure, there might be logs. Keeping logs with (plaintext especially, but not just) passwords is not a good practise.
The server should not store passwords in plaintext. Instead, the password should be stored along with some random salt (more information here: https://security.stackexchange.com/questions/111893/how-to-use-password-salt-the-right-way), not in a plaintext form. One way functions such as PBKDF2, Rfc2898DeriveBytes, Argon2, password_hash or Bcrypt can be used for example. These have the advantage over salted hashes (https://security.stackexchange.com/questions/51959/why-are-salted-hashes-more-secure-for-password-storage), that they also add some extra CPU time (~100ms), delaying an attacker who is attempting a brute-force attack, thus they should be preferred (thanks zaph for the update).
In general, if the server gets compromised, reading the logs is just one way for the attacker to get user information. Enhancing the authentication security is closely related to keeping attackers off your servers, once you are already using SSL and not sending credentials as part of the domain name (thus, in plaintext). Using salted hashes is a must (so that in case of a breach the user passwords remain secure), and from that point on it really depends on your budget. Perfect security is not possible, but the more countermeasures you put in place, the harder it might be for your server to get compromised. But this is a huge and very debatable topic, that cannot be summarised in a StackOverflow answer.
EDIT: Updated to fix current best practise for password storing, based on zaph's comment.

Need cookie to remember two-factor authentication success (not persistent login)

I've read a lot here and other places about using a cookie for a "remember me" option, but what I'm looking for is a way to design a cookie to record success of a two-factor authentication. This is what, for example, Google does: If the second step succeeds (e.g., you entered the code that you received via SMS), then it sets a cookie good for a period of time (e.g., 30 days) that means that the second step can be bypassed. Call this the "verification cookie." My understanding is that if in that time you logout and then in again, it won't do the second step, but only the first step. (I tested this and that seemed to be the case.)
My question is how to design this cookie. One idea is to put the user ID and a 128-bit random number in the cookie, and then to store that number in the database along with the user ID. This is what Charles Miller recommends (http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/) for persistent-login cookies.
However, that's not good enough, I think. The problem is that, since the user is using a two-factor authorization, whatever cookie is used to record that the second step was successful, should be safer than would be the case with a one-factor authorization.
What I want to avoid is this: The cracker has the hashed/salted passwords from the database, and has somehow gotten the password. If he/she has that much, I assume that the 128-bit random number that was in the verification cookie is available as well. (If the cracker has gotten the password some other way, and doesn't have the database, then the verification cookie is safe unless he/she has physical access to the computer. I'm only worried about the compromised database case.)
Maybe an idea is to encrypt the 128-bit random number? (Needs to be 2-way -- not a hash.) The encryption key would be accessible to the application, maybe stored however the database credentials are.
Has anyone implemented what I'm calling a verification cookie (not a persistent login cookie) and can tell me (us) how it was done?
UPDATE: Thinking about this, what would I think be secure enough would be this: Cookie consists of userID and 128-bit random number -- call it R.
Database contains password and R, each hashed and salted (e.g., using PhPass). R is then considered to be a second password. Benefit: Even if first password is bad (e.g., "password1"), R is a very good password. Database really can't be cracked, so it should not be a worry. (I was unnecessarily worried about it, I think.)
I think you have a pretty good plan here. Generally speaking the cookie should be completely random and should not contain any data that is used by the server. The idea is that anything that is client controlled can be tampered with. Even when the value is encrypted, I've seen attackers twiddle bits and get the tampered data to decrypt to a different user's ID (yeah that one scared me a bit). That being said I think Charlie Miller's suggestion is fine, because 128-bits is a good amount of entropy. Me personally, I would go with completely random bytes for a cookie such that no pattern emerges whatsoever.
Our last implementation of a verification cookie was a completely random 256 bit value printed in ascii-hex that was mapped to a user ID and session information in our DB. We kept the session information encrypted with a secret key, so if an attacker SQL injected our DB it would all be useless encrypted info. Of course a total compromise of the DB machine would provide access to the key, but that is a lot harder to do because it involves multiple exploits and pivots.
Some good advice is not to over-think it too much. We ran into implementation problems because we "over-engineered", and in the end we didn't get much security advantage anyway. A simple random number is the best you can do (as long as it is long enough to provide sufficient entropy).
There is a good answer to this problem on the security stackexchange site (which is maybe where this question belongs, anyway):
https://security.stackexchange.com/questions/31327/how-to-remember-a-trusted-machine-using-two-factor-authentication-like-googles

Signed session cookies. A good idea?

In an effort to increase performance, I was thinking of trying to eliminate a plain 'session cookie', but encrypt all the information in the cookie itself.
A very simple example:
userid= 12345
time=now()
signature = hmac('SHA1',userid + ":" + time, secret);
cookie = userid + ':' + time + ':' + signature;
The time would be used for a maximum expirytime, so cookies won't live on forever.
Now for the big question: is this a bad idea?
Am I better off using AES256 instead? In my case the data is not confidential, but it must not be changed under any circumstances.
EDIT
After some good critique and comments, I'd like to add this:
The 'secret' would be unique per-user and unpredictable (random string + user id ?)
The cookie will expire automatically (this is done based on the time value + a certain amount of seconds).
If a user changes their password, (or perhaps even logs out?) the secret should change.
A last note: I'm trying come up with solutions to decrease database load. This is only one of the solutions I'm investigating, but it's kind of my favourite. The main reason is that I don't have to look into other storage mechanism better suited for this kind of data (memcache, nosql) and it makes the web application a bit more 'stateless'.
10 years later edit
JWT is now a thing.
A signed token is a good method for anything where you want to issue a token and then, when it is returned, be able to verify that you issued the token, without having to store any data on the server side. This is good for features like:
time-limited-account-login;
password-resetting;
anti-XSRF forms;
time-limited-form-submission (anti-spam).
It's not in itself a replacement for a session cookie, but if it can eliminate the need for any session storage at all that's probably a good thing, even if the performance difference isn't going to be huge.
HMAC is one reasonable way of generating a signed token. It's not going to be the fastest; you may be able to get away with a simple hash if you know about and can avoid extension attacks. I'll leave you to decide whether that's worth the risk for you.
I'm assuming that hmac() in whatever language it is you're using has been set up to use a suitable server-side secret key, without which you can't have a secure signed token. This secret must be strong and well-protected if you are to base your whole authentication system around it. If you have to change it, everyone gets logged out.
For login and password-resetting purposes you may want to add an extra factor to the token, a password generation number. You can re-use the salt of the hashed password in the database for this if you like. The idea is that when the user changes passwords it should invalidate any issued tokens (except for the cookie on the browser doing the password change, which gets replaced with a re-issued one). Otherwise, a user discovering their account has been compromised cannot lock other parties out.
I know this question is very old now but I thought it might be a good idea to update the answers with a more current response. For anyone like myself who may stumble across it.
In an effort to increase performance, I was thinking of trying to
eliminate a plain 'session cookie', but encrypt all the information in
the cookie itself.
Now for the big question: is this a bad idea?
The short answer is: No it's not a bad idea, in fact this is a really good idea and has become an industry standard.
The long answer is: It depends on your implementation. Sessions are great, they are fast, they are simple and they are easily secured. Where as a stateless system works well however, is a bit more involved to deploy and may be outside the scope of smaller projects.
Implementing an authentication system based on Tokens (cookies) is very common now and works exceedingly well for stateless systems/apis. This makes it possible to authenticate for many different applications with a single account. ie. login to {unaffiliated site} with Facebook / Google.
Implementing an oAuth system like this is a BIG subject in and of itself. So I'll leave you with some documentation oAuth2 Docs. I also recommend looking into Json Web Tokens (JWT).
extra
A last note: I'm trying come up with solutions to decrease database
load. This is only one of the solutions I'm investigating
Redis would work well for offloading database queries. Redis is an in memory simple storage system. Very fast, ~temporary storage that can help reduce DB hits.
Update: This answer pertains to the question that was actually asked, not to an imagined history where this question was really about JWT.
The most important deviations from today's signed tokens are:
The question as originally posed didn't evince any understanding of the need for a secret in token generation. Key management is vital for JWT.
The questioner stated that they could not use HTTPS, and so they lacked confidentiality for the token and binding between the token and the request. In the same way, even full-fledged JWT can't secure a plain HTTP request.
When the question was revised to explain how a secret could be incorporated, the secret chosen required server-side state, and so fell short of the statelessness provided by something like JWT.
Even today, this homebrew approach would be a bad idea. Follow a standard like JWT, where both the scheme and its implementations have been carefully scrutinized and refined.
Yes, this is a bad idea.
For starters, it's not secure. With this scheme, an attacker can generate their own cookie and impersonate any user.
Session identifiers should be chosen from a large (128-bit) space by a cryptographic random number generator.
They should be kept private, so that attackers cannot steal them and impersonate an authenticated user. Any request that performs an action that requires authorization should be tamper-proof. That is, the entire request must have some kind of integrity protection such as an HMAC so that its contents can't be altered. For web applications, these requirements lead inexorably to HTTPS.
What performance concerns do you have? I've never seen a web application where proper security created any sort of hotspot.
If the channel doesn't have privacy and integrity, you open yourself up to man-in-the-middle attacks. For example, without privacy, Alice sends her password to Bob. Eve snoops it and can log in later as Alice. Or, with partial integrity, Alice attaches her signed cookie to a purchase request and sends them to Bob. Eve intercepts the request and modifies the shipping address. Bob validates the MAC on the cookie, but can't detect that the address has been altered.
I don't have any numbers, but it seems to me that the opportunities for man-in-the-middle attacks are constantly growing. I notice restaurants using the wi-fi network they make available to customers for their credit-card processing. People at libraries and in work-places are often susceptible to sniffing if their traffic isn't over HTTPS.
You should not reinvent the wheel. The session handler that comes with your development platform far is more secure and certainly easier to implement. Cookies should always be very large random numbers that links to server side data. A cookie that contains a user id and time stamp doesn't help harden the session from attack.
This proposed session handler is more vulnerable to attack than using a Cryptographic nonce for each session. An attack scenario is as follows.
It is likely that you are using the same secret for your HMAC calculation for all sessions. Thus this secret could be brute forced by an attacker logging in with his own account. By looking at his session id he can obtain everything except for the secret. Then the attacker could brute force the secret until the hmac value can be reproduced. Using this secret he can rebuild a administrative cookie and change his user_id=1, which will probably grant him administrative access.
What makes you think this will improve performance vs. secure session IDs and retrieving the userid and time information from the server-side component of the session?
If something must be tamper-proof, don't put it in the toddlers' hands. As in, don't give it to the client at all, even with the tamper-proof locking.
Ignoring the ideological issues, this looks pretty decent. You don't have a nonce. You should add that. Just some random garbage that you store along with the userid and time, to prevent replay or prediction.

Is this a reasonable way to implement 'remember me' functionality

If a user logs into the site, and says 'remember me', we get the unique identifier for the user, encrypt this with RijndaelManaged with a keysize of 256 and place this in a httponly cookie with a set expiration of say.. 120 days, the expiration is refreshed each successful request to the server.
Optionally we generate the initialization vector based upon the user agent and part of the ipv4 address (the last two octets).
Obviously theres no real expiration system built into this, the user could technically use this encrypted key forever (given we don't change the server side key)..
I considered the fact that to allow this feature I need to allow the user to be able to bypass the login and give me their unique id (which is a guid), I figured the guid alone was really hard to guess a real users guid, but would leave the site open to attack by botnots generating guids (I've no idea how realistic it is for them to find a legit guid).. so this is why theres encryption where the server knows the encryption key, and optionally the iv is specific to the browser and ip part.
Should I be considering a different approach where the server issues tickets associated to a user, and these tickets would have a known expiration date so the server stays in control of expiration? should I really care about expiration? remember me is remember me after all?
Looking forward to being humbled ;),
Cheers.
Very similar question.
The solution to your question is in this blog post
"Persistent Login Cookie Best
Practice," describes a relatively
secure approach to implementing the
familiar "Remember Me" option for web
sites. In this article, I propose an
improvement that retains all the
benefits of that approach but also
makes it possible to detect when a
persistent login cookie has been
stolen and used by an attacker.
As Jacco says in the comments: for in depth info about secure authentication read The Definitive Guide To Website Authentication.
Did you consider something like Open Id? As SO uses.
How important is the information that is being remembered? If it's not going to be anything very personal or important, just put a GUID in the cookie.
Including the IP address in the calculation is probably a bad idea, as it would make users using public networks be instantly forgotten.
Using brute force to find GUIDs is ridiculous, as there are 2128 possibilities.

How does hashing and salting passwords make the application secure?

As much as I understand it is a good idea to keep passwords secret from the site administrator himself because he could try to take a user's email and log into his mailbox using the same password (since many users use the same password everywhere).
Beyond that I do not see the point. I know it makes more difficult the dictionary attack but... if someone unauthorized got into the database, isn't it too late to worry about passwords? The guy has now access to all tables in the database and in a position to take all the data and do whatever he wants.
Or am I missing something?
The bigger problem is that people tend to use the same password everywhere. So if you obtain a database of usernames and unsalted passwords, chances are good they might work elsewhere, like hotmail, gmail etc.
The guy might be in a position to do everything he/she wants to your system, but you shouldn't allow him/her to do anything with other systems (by using your users' passwords).
Password is a property of your users. You should keep it safely.
Many of your users use the same credentials (usernames/passwords) at your site as they do at their bank. If someone can get the credentials table, they can get instant access to a bunch of bank accounts. Fail.
If you don't actually store passwords, then attackers can't steal your users' bank accounts just by grabbing the credentials table.
It relies on the fact that a hash is a one way function. In other words, its very easy to convert a password into a hash, but very difficult to do the opposite.
So when a user registers you convert their chosen password into a hash and store it. At a later point they login using their password and you convert the password to its hash and compares it this is because, to a high level of probablity if (passwordhashA == passwordhashB) then passwordA=passwordB.
Salting is a solution to a related problem. If you know that someones passwordhash is, say ABCDEF, then you can try calcuolating hashes for all possible passwords. Sooner or later you may find that hash('dog') = ABCDEF, so you know their password. This takes a very long time, but the process can be speeded up by using pre-created 'dictionaries' where, for a given hash you can look up the corresponding password. Salting, however means that the text that is hashed isnt a simple english word, or a simple combinationofwords. For example, the case I gave above, the text that would be hashed is not 'dog', but is 'somecrazymadeuptextdog'. This means that any readily available dictionary is useless, since the likelyhood of it containing the hash for that text is a lot less than the likelihood of it containing the hash for 'dog' This likelihood becomes even lower if the salt is a random alphanumeric string.
The site admin may not be the only person who gets access to your password. There is always the possibility of a dump of the whole database ending up on a public share by accident. In that case, everybody in the world who has internet access could download it and read the password which was so conveniently stored in cleartext.
Yes, this has happened. With credit card data, too.
Yes, it is highly probable that it will happen again.
"if someone unauthorized got into the database, isn't it too late to worry about passwords?"
You're assuming a poor database design in which the authorization data is comingled with application data.
The "Separation of Concerns" principle and the "Least Access" principle suggest that user credentials should be kept separate from everything else.
For example, keep your user credentials in an LDAP server.
Also, your question assumes that database credentials are the only credentials. Again, the least access principle suggests that you have application credentials which are separate from database credentials.
Your web application username and password is NOT the database username and password. Similarly for a desktop application. The application authentication may not necessarily be the database authentication.
Further, good security suggests that access to usernames and passwords be kept separate from application data. In a large organization with lots of database users, one admin should be "security officer" and handle authentication and authorization. No other users can modify authorization and the security officer is not authorized to access application data.
It's a quick audit to be sure that the security officer never accesses data. It's a little more complex, but another audit can be sure that the folks with data authorization are real people, not aliases for the security officer.
Hashed passwords is one part of a working security policy.
Of course, storing hashes of passwords instead of plain-text does not make your application secure. But it is one measure that increases the security. As you mentioned if your server is comprised this measure won't save you, but it limits the damage.
A chain is only as strong as its weakest link
Hashing passwords is only strengthening one link of the chain. So you will have to do more than that.
In addition to what has already been said regarding salting, there's another problem salting solves :
If you use the same salt everywhere (or no salt at all), it's possible to say just by looking at the database that user foo and user bar both have the same password (even if you don't know what the password is).
Then, if one achieve to get foo's password (using social engineering for example), bar's password is known as well.
Also, if the salt is everywhere the same, one can build up a dictionary dedicated to this specific salt, and then run a brute-force attack using this 'salted' dictionary.
This may be a bit off topic, but once in a while, I notice some websites are not using hashing (for example, when I click the forgot password button, they send me my password in cleartext instead of allowing me to chose another one).
I usually just unsubscribe, because I don't think I can trust a website designed by people not taking the elementary precaution of hashing passwords.
That's one more reason for salting:)
People seem far too complacent about this! The threat isn't some guy with shell access to your system or to the backup media, it could be any script kiddie who can see the unprotected (but dynamic) part of your site(*) and a single overlooked SQL injection threat. One query and suddenly he can log in as any user, or even as an admin. Hashing the passwords make it far less likely that the attacker can log in as any particular user using their password -or- update a record with their own password.
(*) "unprotected" includes any part of the site that can be accessed as a self-registered user. Contrast this to a bank site, for instance, where you must have an existing bank account to gain access to much of the site. An attacker could still open a bank account to gain access to the site, but it would be far easier to send big guys with bigger guns after him when he tries to crack the system.

Resources