I am currently developping a platform with a PHP framework for our client.
The head of the client's IT department wants us to handle authentication with one database field containing email+password+salt (hashed) so there isn't a plain text email field in this table and the password is more secure (his reasoning). The user should be able to login with his email address and password. So the email address serves as the username.
The idea behind this is that the email addresses of the users are very important for the business of our client and the IT head wants to obscure the email address in the login table in case of a possible attack. (e.g. a hacker gets access to the login table)
This is of course only possbile, because the hashed email adress for the login is linked to his email address in the profile table.
Basically there are two tables which are required for this process to work. The tables are in the same database of course.
One login table with the hash combination field (email, pw, salt) and one profile table which contains among other things the email in plaintext in one field. Let's call it profile_email.
I have strongly recommended not to use this solution, because I have never before heard of this and I have already identified some possible problems with this solution.
So my questions are: Is this a safe and feasible solution? Can you think of any unforeseeable problems? Have you heard of similar solutions?
from an entity-relationship-point-of-view ...
you have a login table that either contains a field that is a concatination of hashes or a hash of a concatination of string values ...
you have a profile table that conatins the usual profile info, including a sensitive info (email)
if those two are linked by a key, the simple hashing of that email address is useless, since the same info is available as a clear text string from the profile table
in the other case, when in the login table it is ONE hash of a concatination of email password and salt, it is no added security, since the link to the profile table reveals a part of the hashed concatination ... since you also have to store the salt, and since that also has to be linked to the login entity or be part of the login entity, an attacker knows all parts of the concatination except the password ...
i can't see why this approach is a good idea, except if you split the database login for authentication from the rest ...
let's say you have in your login table:
s=randomSalt
e=cryptoHash(email,static_system_wide_salt)
p=cryptoHash(password,s)
id=KeyForRelationToOtherEntities
now the database rights to this table are restricted, and only the authenticator_user may access it, but nothing from the rest of the database
the email address in the authentication process is hashed and hardened against rainbowtable attacks
the password too
you can index the e colum for searching during the login process
the authenticator can not access profile information or other information that can be linked to the login entity, since the access rights restrict the authenticator to the login table
the rest of the system can't access the login table for the same reason
one additional role has to be taken into account, regarding password changes and creating new users if the authenticator may only read the login table
... just my 2 cents here ... it's just an idea, and not really complete, or guaranteed to be secure ... just an idea that picks up the general idea of separating the login table
I'm not absolutely clear about your scenario, but i guess it's something like this:
valueToStore = hash(email) + delimiter + hash(password, salt) + delimiter + salt;
This would allow to search for the email, but only if the email is made case insensitive (e.g. lower case). Otherwise you could even get duplicates with the same e-mail address.
Because the hashed email is only part of this field, searching in the database is more difficult and slower. If the user changes his email address, you would have to update both fields, the password table and the profile_email table.
Because the email is available in another table anyway, it is incomprehensible why this should be more secure. If an attacker has read access to the database (e.g. SQL-injection), there is nothing to prevent him from query the other table too.
It would be more safe, if the email would be encrypted (not hashed) in the other table too. Then you can search for the email by hash and nevertheless encrypt the email with an IV.
In every case i would not store the hashed email and the password-hash into a single field. If hashed correctly then other parameters like cost factor and algorithm are also part of the password-hash, this is enough for a single field.
Related
Ok, so I've inherited an open-source project with user logins that are a simple username/password combo. Unfortunately, if someone forgets their password, we don't have a password recovery option. I'm hoping to fix that now, but not sure how to do it securely, given that we don't have any other identifying characteristics. User accounts have no recovery email, no "secret questions," etc.
A user account consists only of 1) username, 2) encrypted password, 3) List of document ids which the user has editor access (but this is publicly visible by viewing the user's public page)
Now that I have access to the project, I will be implementing OAuth or similar, but as for old accounts with forgotten passwords that have since been logged out, is there any right way to ID my users so they can do a password reset?
There is no great way of doing this. You just don't have the information; not even enough to contact users. Until a user has supplied their username and password, you can't communicate with them.
You'll need to add a check that runs every time a user authenticates, which checks if they've set recovery data (email or whatever you decide on). From there you have a variety of options, depending on how important you find the recovery data. In order of severity, you could:
Disallow use of the site until they have added and verified
recovery data. Essentially, full authentication fails if recovery
data is not set.
Prompt them to add recovery data, but allow them to skip it.
Notify them that the ability to set recovery data has been added, but take no further action.
If you are dramatically changing login, you'll need to support the legacy method as well until such time as you want to abandon users who haven't made the switch.
On our website, we have existing users who use username(=email address) and password to authenticate. Now we also want to offer "Sign in with LinkedIn" because we know that a huge fraction of our users is also on LinkedIn. Doing this is technically not too challenging with PHP.
For new registered users via "Sign in with LinkedIn", I would store their LinkedIn ID upon registration, so this is nothing they can manipulate. So when they return, it's an easy decision: Check the LinkedIn ID, if it is known than all is good.
Now comes the tricky question: If an existing user decides to use "Sign in with LinkedIn" for the first time, is it enough to check if we have his email address in our database and then assume that it is him/her? Should we check additional data or...?
Thanks for any hints!
Since email address is unique key and it represent the username, i think you don't need any additional data to check if it is him since his/her password is equivalent to the linkedIn email address.
For a web application, where we need to store and manage users (SSO or openauth or what not is off the table), where we manage important business data, how risky is it to use an email address + password as the sign in?
For the last 15 years or so, encryption and protection techniques have improved, but we continue to use a proprietary user id, akin to using your bank card number for online banking; an id that will not be reused elsewhere. Customers and product owners are pushing to use email address because it is easier to remember.
I am concerned that there are a lot of websites that collect email + password pairs in order to use them to try to hack other sites; presumably asking you to sign up for an account for some humble service or other. What is this activity called?
I'm looking for some article or argument why using email+password for a site with sensitive business/financial information would be dangerous; or why it is not so bad. Again, I realize that provisioning our own accounts is not the ideal thing and am not looking for solutions at outsourcing authentication.
The "risk" of using a single authentication method for signing onto your application is difficult to determine without a risk assessment, and clearly defined system boundaries.
NIST 800-61 and NIST 800-63 gives guidelines on authentication methods for different levels of sensitive systems (in your case, a application). It will give you ideas on how to present your argument, and maybe an alternative solution, i.e., multi-factor authentication if the customer wants to authenticate using an e-mail address. This would mitigate the risk associated with malicious websites which collected e-mail addresses and passwords.
Keep in mind, password policy can also be managed to mitigate the risk behind a single authentication method using an e-mail and a compromised password associated with that e-mail.
All in all, it's not the ID that is important, but the authentication method and policies in place to mitigate the risks.
Using email + password as credentials is the widely accepted method of allowing users to log into sites on the web.
The advantage of using email is that everyone remembers their email address, whereas people will have difficulty in remembering which username or user ID they first signed up with if this is not their email address.
Username should not be considered private. This is the job of the password. Encourage your users to use a password manager such as LastPass where it can generate a 20 character completely random password (128 bits - uncrackable) which is different per site. LastPass will remember the username if this is not their email, so that solves this problem, however not using email can bring other problems such as username enumeration. If any signup function asks for a user to specify their username and you say that it is already in use, an attacker can use this to narrow the list of users in order to prepare for a password guessing attack. If you ask for email as step one of password reminder or signup forms, the system can send an email with a password reset link if already registered, or send an email with a link to the next step in the registration process if not.
In the end it all comes down to the value of the data your application is protecting. Adding two factor authentication is always a good step and can protect against password guessing and password reuse.
SSO or openauth or what not is off the table
Why is the case? Can't you use OAuth with claims based authorisation? You can still secure your application and make sure only the correct business users have access - it would just be that another entity is managing access for you.
I am concerned that there are a lot of websites that collect email + password pairs in order to use them to try to hack other sites; presumably asking you to sign up for an account for some humble service or other. What is this activity called?
Credential harvesting?
Just out of curiosity, I wonder why web apps typically user a userID and a password.
I don't see reasons, why a sufficiently long password doesn't fit too. For example, a password generated by a server-application.
Are there reasons an app ultimately has to use a userID too?
As long as password are unique and long, it perfectly allows to identify a user.
For one thing, password resets would be quite complicated without user IDs.
But the real reason would be that it's not possible to use salting to protect passwords if you don't have an user ID, which means that you would effectively not really be protecting your passwords.
Here's why. Salting requires you to know the salt that was used to generate the password hash. The process is as follows:
Locate salt using the User ID in your DB
Salt & Hash the password that was provided
Check whether this matches the password hash you have in the DB.
If you don't have an user ID, you'd need to check your password against every user in your database.
This is equivalent in complexity to checking one password is against your entire database, which is something you purposefully want to make prohibitively expensive (in time or money) by design.
One of the most important reasons why web applications don't use passwords only is that two users could have the same password.
When the password is the only factor to identify a user, user A could log in with his password and would have access to user B's account and not his own account since they use both the same password and the system needs to pick one user to log in.
I had a quick question about cookie security that I wanted to run by the stackoverflow community before I got too far into implementing it. This will be my first time implementing user sign-in on a site and I wanted to be extremely cautious about security so-as not to have to worry about accounts being compromised down the line.
Here's my hypothetical security solution:
User signs up for site (through either email registration, login with Facebook, etc.) and is assigned a User ID number. This number is public and can be used to access the profile of the user, refer to them in posts, and so on.
At registration, the user is also assigned a randomly generated ROWID as their information is stored in a database (hosted on Google Fusion Tables). This ROWID number is kept hidden from the user and is never revealed.
The User ID is encrypted against the ROWID number and this number is stored in a cookie on the user's computer. It isn't ever visible to other users and, in theory, this could only be viewed by the user.
This solution would allow for a "secret" key (the ROWID number), a "consumer" key (saved in the cookie), and a public reference ID (the User ID). All of these are, of course, rolled up into a database where the site can quickly access them. Does this sound like a plan that would provide the proper level of security or is there something else that I should consider?
For additional protection against cookie theft through something like XSS, you might want to consider issuing unique cookies per IP address, and then making sure that the cookies are only useable from that IP address.
If you're storing your cookies in the database, things can get complicated, as you now have multiple cookies mapping to the same user.
Here's how to avoid those problems:
Set-Cookie: userName=Alice; authCode=eeba95a4...
Where: authCode=HMAC(ROWID, userName + ipAddr)
When you receive this cookie, look up the user in the database, recompute/verify the authCode in the cookie, using ROWID and ip address of the request. No need to store cookies in the database.
For extra crypto points, throw a salt parameter into the mix:
Set-Cookie: userName=Alice; salt=59843...; authCode=eeba9...
Where: authCode=HMAC(ROWID, userName + ipAddr + salt)
Salt value is generated randomly for every cookie you produce. There's no need to keep it a secret.
This is a good question, and since you have no answers yet I will give it a go. As far as I can see (I'm not a cryptographic expert) this seems reasonable, at least in theory.
I see one problem, that is if a malicious user get the consumer key (and this is not protected in any way) he could try to brute force the ROWID since he already know the User ID. So at least some kind of salt should be added to the User ID before encrypting. Also the "consumer" key ccokie should be passed as secure only, making sure it never travels on an unencrypted connection.
But it all depends on what you are planing to use the different keys for.