I'm designing a REST API and I have some problems in terms of security for authenticating the user.
For authentication I don't want the password to be send across the network in plain text.
To bypass this problem I could send a SHA-256 hash of the password (with the username as salt), so the password is never sent in plain text. In my database I will be storing the following hashes: SHA256(password + salt) and I'll compare if both of the hashes match.
The problem with this option is that I'll have a hash computed with a fast hash algorithm and the salt is not random.
In security the best practice is to use a slow signature algorithm, with a random salt (like bcrypt).
The slow algorithm is not a problem, i could use bcrypt on the client side, but for the salt i don't know what to do:
Bcrypt need a salt with a defined size so i can't put the username
If i'm using a random salt, how the client will know the value of this salt before computing the password's hash?
So i can see 3 options, but none are sastisfying:
I send the password in plain text (I'm using SSL) and i store bcrypt in the db => still vulnerable to man in the middle
I use SHA256 and send the hash where the salt is the username (still using SSL) => the hash in the db are less secure
I use bcrypt and I have a two step process: i ask for the saltfor a given user and then send the hash of this user (still using ssl) => by trying to log in with an other username i can obtain his salt, not awesome
Is anybody has a better solution or some advices?
I think you might be conflating/confusing a few issues here:
If you're storing the hash(password + username) on the server, and authentication involves sending hash(password + username), you haven't really achieved anything better than just storing the password on the server. The goal of only storing hashes long-term is that if you have a data breach (i.e., an attacker gains access to the database) they still can't produce the correct value to authenticate. But if you're doing a simple comparison, this is still an issue.
The correct use of hashing+salting is: (1) Server stores tuples of (Salt, hash(Password + Salt); (2) User sends (claimed Password); (3) Server computes hash(claimed Password + Salt); (4) if hash(claimed Password + Salt) == hash(Password + Salt), then they're authentic. In this way, even if an attacker gets access to the database, they can't produce a claimed password that such that hash(claimed Password + Salt) is valid.
Sending a plaintext password via SSL is not "in the clear". Per #NullUserException's comment, unless the attacker has broken SSL. Only the server will be able to obtain the value of the password (assuming the server's public key is valid, which is a whole 'nother story).
Hope this helps!
There a couple of advantages to the approach of hashing on the client side. One of them is the server never gets the real passwords, so if the server is compromised in any way, it still won't get the real password. The other one is, it can lighten the load on the server side if you're planning to use slow hashing.
However, hashing passwords is designed to protect you in case the database is breached and hashes are stolen. This means if someone gets a hold of the hashed passwords, they could still impersonate users by sending the hash. The implication is, even if you hash on the client side, you still need to re-hash on the server.
The other potential downside is that this could alienate part of your userbase that doesn't have JavaScript enabled.
To address your points:
Bcrypt need a salt with a defined size so i can't put the username
Don't use the username as a salt. Salts should be unique, and a username (and derivations thereof) is certainly not unique. By unique I don't mean just unique to the server, but unique everywhere. Use a cryptographic nonce instead.
If i'm using a random salt, how the client will know the value of this salt before computing the password's hash?
Just have the server send the salt (nonce) beforehand. You could do this on the client as well, but the Javascript doesn't have a CSPRNG as far as I know, and you'd still need to send the nonce back to the server.
I send the password in plain text (I'm using SSL) and i store bcrypt in the db => still vulnerable to man in the middle
SSL was designed to prevent man in the middle attacks. Unless it's broken somehow, that's not going to be a problem.
I use SHA256 and send the hash where the salt is the username (still using SSL) => the hash in the db are less secure
Don't use username as a salt. And like I said before, you have to hash on the server side regardless of whether or not you did it on the client side.
I use bcrypt and I have a two step process: i ask for the salt for a given user and then send the hash of this user (still using ssl) => by trying to log in with an other username i can obtain his salt, not awesome
Not awesome indeed.
Make the salt constant, let's say make it a hash of the username. So hash_val = HASH(HASH('username') + 'password') is stored server-side.
For authentication your server sends a single-use random value, ie: nonce = HASH(RAND())
Your client computes the following based on the input credentials client_hash = HASH( nonce + HASH(HASH('username') + 'password')) and sends it back to the server.
The server perfoms the same operation, compares the resulting hashes, and discards the nonce.
In this way the hash sent over the wire is used only once and you're protected from 'replay' and MITM attacks.
Also, look into something like PBKDF for storing passwords rather than just hashes, it makes both bruteforcing and rainbow tables completely impractical. Here's the PHP implementation I'm using since it's not in PHP yet.
If possible create API Key and secret key (API username/password, obviously unique for each user) to use API. You should give an option in your site interface to activate/de-active the API access as well as option to re-generate the API Key and secret key. Here, on this interface users will see the API/Secret key of the API.
Related
I'm building a REST API in PHP and I'm currently working on the security side of things.
I have read a lot about network authentication and implemented some suggested strategies.
I'll explain what I've done so far and where I got stuck.
To prevent a hacker from knowing all users' passwords if they got their hands on my database, I keep only a hashed version of the passwords in db. I use the php password_hash() function that creates a salt automatically. Also, the hashed password expires 30 minutes after logging in with the original password.
To prevent sniffers from seeing the hashed password in request headers, the client sends several headers in every request: a timestamp, some random string and a hashed checksum of the combination of hash+timestamp+random_string+url.
Now, my question is what happens when the hash token expires (after 30 minutes)? The user now needs to send their original password to get a new token, but the server only keeps a hash of the original password. Using the checksum method wouldn't work because the server needs the original password to get the right result for hash comparison. So it has no way of knowing the user password is correct.
P.S. I'm not worried about replay attacks at the moment, but if I were to implement security against this kind of attack, would I have to keep a history of all Nonce strings at the client side and all cNonce strings at the server side?
Thank you.
EDIT:
The documentation states that password_hash() uses bcrypt algorithm which handles the creation of a salt automatically.
As for the checksum string, I hash it using the SHA256 algorithm.
Now, my question is what happens when the hash token expires (after 30
minutes)? The user now needs to send their original password to get a
new token, but the server only keeps a hash of the original password.
Simply use the password-verify function to validate the plaintext password sent to you by the client matches your stored hash in your database.
$password is the user supplied password (not a hash).
$hash is the password hash stored in the user's database record, containing the algorithm, salt and hash.
Complexity is the enemy of security. Keep things as simple as possible. Ensure your connection is over HTTPS - this will encrypt and verify the password data in transit and HTTPS uses TLS/SSL which also prevents replay attacks.
I am currently working on a mobile app that has a accompanying web service being developed in PHP. The one thing that we want to make sure is that the users data is safe in every possible way.
After careful evaluation, we have decided to use RNCryptor for all things related to encryption. This is in addition to the HTTPS connection. The current process is like below (login example):
The RNCryptor library on iOS uses a key to encrypt password before sending it to the server.
The server then stores this encrypted password on the database.
While re-authneticating, the app sends the password (again encrypted with the static key) and the server decrypts it (means the server also has the encryption key), verifies the login and sends the login key (encrypted with the same static key) back to the client.
Every subsequent request relies on the encrypted loginKey and the username for authenticating the validity of the user and login session.
I believe the above system is flawed because of the STATIC encryption keys and since the key is available on both the server and the client.
What we would like is to make the encryption key dynamic by merging the raw password with the STATIC encryption key. This would make encryption key unique for each user but it also means the server will have no idea about the key. It is essential for the server to know the key since other user data also gets encrypted and decrypted based on this key.
Can somebody help me out with this? What steps do I need to take to make the system more secure? Any code snippet or reference link specific to server-mobile client would also do. I know there are a lot of tutorials out there but mostly all resume the client to web based and not mobile.
PS: Sorry for such a long post.
I would probably just use OATH2 tokens for authentication, but if you wanted to do it your own way...
For securing passwords a salted hash is used. As a basic example of hashing passwords with a salt consider the following, and keep in mind it's NOT cryptographically secure.
shaResult = SHA1(16 Byte Random Salt | "p#ssword")
Basics: The server stores the shaResult. Your app stores the salt value generated. When the user types in their password you append it to the stored salt, hash it, and send it to the server for verification. There's really no need to encrypt it to the server now. The HTTPS connection should handle that.
Good cryptographic password hashing is described in detail at Salted Password Hashing - Doing it Right To summarize they suggest using the following:
Salt should be generated using a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG). Suggested CSPRNGs is given in the link for multiple programming/scripting languages.
The salt needs to be unique per-user per-password. Every time a user creates an account or changes their password, the password should be hashed using a new random salt. Never reuse a salt. The salt also needs to be long, so that there are many possible salts. As a rule of thumb, make your salt is at least as long as the hash function's output. The salt should be stored in the user account table alongside the hash.
Use a well-tested cryptographic hash algorithm, such as SHA256, SHA512, RipeMD, WHIRLPOOL, SHA3, etc.
Use slow hashing functions that perform multiple iterations. Standard algorithms include PBKDF2 and bcrypt.
Use a keyed hashing algorithm, HMAC.
I'll reiterate that secure connections still need to be used in conjunction with the above.
If you want a method that does not use the same authentication value each time consider using the Challenge-Handshake Authentication Protocol which protects against replay attacks. See RFC1994 for more complete details.
At setup a shared key is established between the client and server. This must be done securely, possible with SSL or side-channed communications.
Authentication:
The server sends a random challenge to the client.
The client uses the challenge value to compute a hash with a function such as PBKDF2 and sends it to the server along with the user identifier.
The server performs the same computation and verifies the value from it's user identifier/shared key table.
There are slight variations but the concept is the same.
I have read in many articles that we should combine an unique salt to each passwords before hashing and store the salt in database for verification but How about using the password itself as an salt ?
Doing this will benefit as the salt will be unique for each as well as it will be hidden as it will be stored no where.
An simple example I can give for above is:
$hashToStore=sha1(strrev($password).$password);
Above I am just reversing the password and using it as an salt (I will be doing something more complex then just reversing it in development.)
Is This an better way for storing passwords or will be a bad practice.
PS:I am completely aware of php latest inbuilt functions such as crypt() and use it in real world, but yet wanted an review for above.
A common mistake is to use the same salt in each hash. Either the salt is hard-coded into the program, or is generated randomly once. This is ineffective because if two users have the same password, they'll still have the same hash. An attacker can still use a reverse lookup table attack to run a dictionary attack on every hash at the same time. They just have to apply the salt to each password guess before they hash it. If the salt is hard-coded into a popular product, lookup tables and rainbow tables can be built for that salt, to make it easier to crack hashes generated by the product.
A new random salt must be generated each time a user creates an account or changes their password.
[…] It's easy to get carried away and try to combine different hash functions, hoping that the result will be more secure. In practice, though, there is very little benefit to doing it. All it does is create interoperability problems, and can sometimes even make the hashes less secure. Never try to invent your own crypto, always use a standard that has been designed by experts. Some will argue that using multiple hash functions makes the process of computing the hash slower, so cracking is slower, but there's a better way to make the cracking process slower as we'll see later.
Here are some examples of poor wacky hash functions I've seen suggested in forums on the internet.
md5(sha1(password))
md5(md5(salt) + md5(password))
sha1(sha1(password))
sha1(str_rot13(password + salt))
md5(sha1(md5(md5(password) + sha1(password)) + md5(password)))
Do not use any of these.
Salt should be generated using a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG). CSPRNGs are very different than ordinary pseudo-random number generators, like the "C" language's rand() function. As the name suggests, CSPRNGs are designed to be cryptographically secure, meaning they provide a high level of randomness and are completely unpredictable. We don't want our salts to be predictable, so we must use a CSPRNG. The following table lists some CSPRNGs that exist for some popular programming platforms. (PHP: mcrypt_create_iv, openssl_random_pseudo_bytes)
The salt needs to be unique per-user per-password. Every time a user creates an account or changes their password, the password should be hashed using a new random salt. Never reuse a salt. The salt also needs to be long, so that there are many possible salts. As a rule of thumb, make your salt is at least as long as the hash function's output. The salt should be stored in the user account table alongside the hash.
To Store a Password
Generate a long random salt using a CSPRNG.
Prepend the salt to the password and hash it with a standard cryptographic hash function such as SHA256.
Save both the salt and the hash in the user's database record.
To Validate a Password
Retrieve the user's salt and hash from the database.
Prepend the salt to the given password and hash it using the same hash function.
Compare the hash of the given password with the hash from the database. If they match, the password is correct. Otherwise, the password is incorrect.
At the bottom of this page, there are implementations of salted password hashing in PHP, C#, Java, and Ruby.
In a Web Application, always hash on the server
If you are writing a web application, you might wonder where to hash. Should the password be hashed in the user's browser with JavaScript, or should it be sent to the server "in the clear" and hashed there?
Even if you are hashing the user's passwords in JavaScript, you still have to hash the hashes on the server. Consider a website that hashes users' passwords in the user's browser without hashing the hashes on the server. To authenticate a user, this website will accept a hash from the browser and check if that hash exactly matches the one in the database. This seems more secure than just hashing on the server, since the users' passwords are never sent to the server, but it's not.
The problem is that the client-side hash logically becomes the user's password. All the user needs to do to authenticate is tell the server the hash of their password. If a bad guy got a user's hash they could use it to authenticate to the server, without knowing the user's password! So, if the bad guy somehow steals the database of hashes from this hypothetical website, they'll have immediate access to everyone's accounts without having to guess any passwords.
This isn't to say that you shouldn't hash in the browser, but if you do, you absolutely have to hash on the server too. Hashing in the browser is certainly a good idea, but consider the following points for your implementation:
Client-side password hashing is not a substitute for HTTPS (SSL/TLS). If the connection between the browser and the server is insecure, a man-in-the-middle can modify the JavaScript code as it is downloaded to remove the hashing functionality and get the user's password.
Some web browsers don't support JavaScript, and some users disable JavaScript in their browser. So for maximum compatibility, your app should detect whether or not the browser supports JavaScript and emulate the client-side hash on the server if it doesn't.
You need to salt the client-side hashes too. The obvious solution is to make the client-side script ask the server for the user's salt. Don't do that, because it lets the bad guys check if a username is valid without knowing the password. Since you're hashing and salting (with a good salt) on the server too, it's OK to use the username (or email) concatenated with a site-specific string (e.g. domain name) as the client-side salt.
source: https://crackstation.net/hashing-security.htm
So, to answer your question, bad idea, very bad idea.
Please, don't ever do this. The whole point of salting is that every persons password hash will be unique which removed the issues of rainbow tables and giving away who has the same password.
Why does that matter? Look at the LinkedIn hack where they had "password hints". People has hints like "rhymes with assword" which gave away what their password, and also their hash was. It also gave away EVERYONE ELSE who was using the same password.
I'm working on an application for iOS which will have the user fill out their password. The password will then be posted to a PHP page on my site using either POST or GET. (It must be plaintext because it is used in a script.)
Besides HTTPS, is there any way to secure the password? Encrypt it in Obj-C and then decrypt it in PHP?
NOTE: The username is not sent... only the password is posted to the server.
EDIT:
To clarify, David Stratton is correct... I'm trying to prevent malicious sniffers in public locations from simply reading clear text passwords as they are posted to the server.
Challenge response outline
Lets assume you have one-way hash function abc (in practice use md5 or sha1 a cryptographically strong hashing algorithm for PHP see: password_hash).
The password you store in your database is abc(password + salt) (store the salt separately)
The server generates a random challenge challenge and sends it to the client (with the salt) and calculates the expected response: abc(challenge + abc(password + salt))
The client then calculates: abc(user_password + salt) and applies the challenge to get abc(challenge + abc(user_password + salt)), that is sent to the server and the server can easily verify validity.
This is secure because:
The password is never sent in plaintext, or stored in plaintext
The hash value that is sent changes every time (mitigates replay attack)
There are some issues:
How do you know what salt to send? Well, I've never really found a solution for this, but using a deterministic algorithm to turn a username into a salt solves this problem. If the algorithm isn't deterministic an attacker could potentially figure out which username exists and which do not. This does require you to have a username though. Alternatively you could just have a static salt, but I don't know enough about cryptography to assess the quality of that implementation.
Reconsider not using HTTPS. HTTPS a good defense against a number of attacks.
There usually isn't a reason to transmit a password. By transmitting passwords, you are sending valuable data and their is extra risk associated with it.
Usually you hash the password and submit the hash. On the server side, you compare the hashes, if they match, great.
Obviously with this approach, the hash is important, and you have to secure against a replay attack. You could have your server generate a crypto-secure one-time use salt, pass that to the client, salt and hash the password, and compare the hashes serverside.
You also need to guard against a reverse hash attack on password. IE, I have a hash, and I can compare it to a bunch of pre-generated hashes to find the original password.
You could encrypt at the device and decrypt at the server, but if the data going across the wire is sensitive enough to warrant that much work, then IMHO, I believe you're better off just using https. It's tried, true, and established.
It's not perfect, mind you, and there have been successful attacks against older versions of it, but it is a heck of a lot better than "rolling your own" method of security.
Say your key gets compromized, for example: If you're using https with a cert from a trusted authority, then you just buy a new cert. HTe deveice, if it trusts the authority, will accept the new certificate. If you go your own route on it, then you have to update the keys not only on your web server, but at the client as well. No way would I want that sort of headache.
I'm not saying that the challenge is insurmountable. I am saying it may not be worth the effort when tools already exist.
I wish to build a private data transmission and protection scheme for user login function on my website. The private data I wish to protect is the user id and the password.
My requirements for this scheme include: Secure data transmission (without SSL, TCL), highly safe storage (once lose password, data becomes sort of unrecoverable)
I have drafted one listed below:
RSA (encryption and decryption on client and server sites respectively)
In detail, I plan to use Javascript to encrypt user id and password on the client site, and PHP to generate private & public keys and decrypt the received cipher text on the server site.
SHA256/SHA512/Twice MD5 (on server site, encryption using random Salt which is bidden with user ID)
Using PHP to re-encrypt the plain password with SHA256 algorithm with a user id binding salt.
Is this a good solution to meet my requirement? thanks
The best way to make sure your password can't be intercepted, ist to not transmit it: This is much easier than one might think:
On the server side, store the passowrds salted and hashed (There are thousands of articles on how to do this properly)
When a user on the client logs in, he inputs username and password
With the username, request the salt from the server (e.g. via AJAX). This is not a security problem, as the salt is not secret. In the same reply send the server timestamp.
On the client create the salted hash, this results in a secret, that both parties know, even if it never has crossed the wire. Keep it.
Use the server timestamp and the client local time to calculate a time offset and keep it - you will need it to avoid replay attacks.
You can now use this secret (salted password hash) and the timestamp to securely transmit whatever you want: For a request, salt the passhash with the (offset-corrected) timestamp and some entropy, hash again. Use this as a key to encrypt (AES comes to mind) your message to the server, sending the timestamp and random salt along
On the server reject timestamps older than a few seconds to be replay safe
On the server use the provide timestamp and salt to recreate the key for this message
Crypto-js has the JS parts you need
And a bad news for us :( RSA 1024 bit was cracked in 100 hours! Here is the article:
1024-bit RSA encryption cracked by carefully starving CPU of electricity