Im dealing with legacy code here.
There's a HTML form with username/password inputs.
The form is then sent to the server (using SSL), and the password is compared to the database value.
Question: is there a way to "hide"(encrypt) the password while it is sent to the server?
Even if I'm storing the hashed-password and unique user-salt in the database,
the password is at risk while being sent by the user.
How do the professionals do it?
**EDIT:
Im planning on storing the password as a hash, with a unique salt.
If anyone gets a hold of the password (if SSL is compromised) does that mean that a hacker can gain access without a problem?
In a regular username/password login, the password is always sent to the server. Ideally, the server then hashes the password input and compares to the hash stored in the database - using a unique salt for every password. Like #Sneftel said, when you use SSL the passwords aren't being sent in plaintext.
Think about it; if only the password hash was sent to the server, and the server compares that to the hash in the database - how would that be any different from just storing the passwords in plaintext in the database? It would be enough for any attacker to get the hash in order to get entry into the system.
The security issue here would be that the password themselves are stored in plaintext in your database - that's not a good idea. There are a few tips here: http://alias.io/2010/01/store-passwords-safely-with-php-and-mysql/
You may use some javascript program at client side to encrypt the password. But that requires the user to execute that script, which can be a problem:
Some users cannot execute that script, because they access your page with a program that does not support javascript. An example could be a program that is intended to load the page and get some specific value out of it.
Some users don't want to execute that script.
So, hiding the password while being sent to the server is not that easy.
Anyway, you mentioned that you send the data using an SSL-encrypted connection. That is the usual (and usually secure) approach for that situation. The disadvantage is that, if your SSL implementation has a flaw (eg. the Heartbleed bug), your passwords are usually broken, unless you do not use the server key for encrypting the connection data (this is called Perfect Forward Secrecy).
Regarding your database, you should never store plain-text passwords in it, unless you are required to do so without the possibility of changing that requirement. You always should store the salted password hashes.
Related
Please follow thread below in comments for further clarity if anyone else has the same question
I'm not very knowledgeable in web security setup. Is it reasonable to store a hashed username and password in a php file inside a variable?
For instance I have a login form, on submit it hashes the username and password into a cookie. Than matches the hashed cookie to the hashed variables on the sever to allow access.
These are also one way hashes.
The problem is not in storing the hash in PHP itself; although a database is generally recommended.
The problem is using the hash as a plain-text password/secret; this is no different than any plain-text password. If someone was able to view the PHP source code they would have the hash and thus 'password'. Remember, password hashes are not secrets even though they should generally be treated confidentially1.
Instead, accept the username/password as plain-text - although, do use SSL to encrypt the password over the connection - and verify this against the hash2. At no point is a hash from the user trusted - as it cannot be proved that it was generated from an actual secret.
Once the submitted username/password has been validated on the server against the stored hash then a session nonce is established; it is this unguessable per-session secret that is then used to re-validate/authorize the user each subsequent request3. This is 'automatically handled' in PHP when creating a new session.
See the "Do's and Don'ts" and "Don't write your own password checker" answers, which are especially pertinent.
1 In real-world applications there should be a high priority given to confidentiality and preventing unauthorized disclosure. This is because most user choose stupidly short or common passwords (at least when given the chance) that can be brute-forced quickly. This can be mitigated by encouraging secure passphrase usage and secondary validators.
2 The newer password_verify / password_hash (or an equivalent library / backport) functions should be used as these correctly handles basic details including
Applying a correctly generated salt which prevents rainbow table attacks, and
Using an appropriate (ie. bcrypt) hash function which mitigates brute-force attacks on strong passwords/passphrases.
(If planning on using SHA - don't! - for hashing passwords, stop and read the links..)
3 Unlike using a hash-as-a-password this is only susceptible to session-hijacking, even if the hash in the PHP source code were leaked: it is also unique per-session. The attacker needs access to the client's cookies (via local access or Cross-site scripting (XSS); XSS can be mitigated with HTTP-Only cookies) or a method of intercepting the HTTP request (which can be mitigated with HTTPS); then, within that session, an attacker could impersonate the authenticated client.
As a long aside: if there was a need to store data in cookie (or otherwise sent back with a server request) and to ensure that it came from the server to begin with, one solution would be to use an HMAC as an authentication code. But this does not apply here.
User name/password authentication has a well tested solution that should not be modified.
When you store a password, use PHP's password_hash function.
password_hash("rasmuslerdorf", PASSWORD_DEFAULT)
is a typical use case. This creates what people loosely refer to as a hash. It's not really a hash as it uses bcrypt, a key derivation function, but everyone refers to them as hashes. Store the password alongside the username. You can do this in a database or a flat file. You should do your best to keep this secure to prevent offline attack, but this hash is relatively secure against all but a very determined and well equipped attacker.
When the use logs in, pass their username and their clear text password to the server. The server should obtain the user's stored password hash using the username as the key. Then the server validates the password using PHP's password_verify.
All you've done here is substitute one password for another password. It is vulnerable to replay attacks. And that you are storing the effective password in a cookie opens up a world of exploits.
There are lots of good tutorials on PHP authentication on the internet, and a few bad ones. You should:
Use PHP sessions (with a session cookie)
Use https (and HSTS)
Send the submitted values serverside in a post for validation
On the server lookup the hashed password and random salt stored against the username
Hash the submitted password with the stored salt
If it matches the stored hash you have a successful authentication; regenerate the session id and continue.
Otherwise track and limit the number of failed attempts to prevent brute forcing.
provide an explicit logout function which removes the data in $_SESSION
Not enough but it's good as start.
Cookies still a security problem as it can be used in attacks since the hash is stable result whatever it was MD5 or whatever.
In Wordpress they use a good strategy which is "Salt Keys" this makes application secure and hard to get cracked
I know this question sounds like it might already be answered but stay with me. I have a website that needs users to sign up and log in. In this process, lets take sign up the user would provide a username and password, the system will check the information and then POST to itself for the PHP script to salt and hash the password before storing it in the database.
Now i thought this was safe, salt and hashing a password is always best practice but recently i thought about how this is happening, the data has to be sent to the server before it can be hashed up and because i don't use SSL the username and password are sent unencrypted, so would i be right in assuming that this information would be sent in plain text?
If so, this isn't good at all. So the only two ways i can see about getting through this is either:
Using SSL and securing the connection between the user and the server and encrypting the data being sent.
Hashing the information before it leaves the user, this could be done using Javascript
I want to implement the second but I'm not sure of how to do this. What would be the best practise for this?
I was thinking before the information is sent a AJAX script will take control of the data and check to see if first the information is what we're looking for and then salt and hash the information.
Are there any security implications on this implementation I have described?
Thanks for your time.
Using SSL and securing the connection between the user and the server and encrypting the data being sent.
Yes, do this.
Hashing the information before it leaves the user, this could be done using Javascript
This will not secure the data. Instead, it would effectively change the secret data to be sent to the server to the hashed version of the password. That would still be sent as plain text and attackers could sniff it and know exactly what to send.
You might be interested in the Secure Remote Password protocol.
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 am creating a program that communicates with a PHP script on a web server and to do so I need to be able to pass parameters from the program to the PHP script.
Now here is my question. At some point the user name and password needs to be passed to the script. Now this is not done in a way that is apparent to users (such as in an address bar) but I know with a little sniffing around someone that really wanted to could figure it out. So while my script is safe from injection, obviously variable tampering is an issue here.
This is an idea I have come up with so please help me wrap my head around it and see if this would work the way I THINK it will.
My thought was to encrypt the user password (or another unique key) variables on the client side before sending so you get a url like (obviously just made up) mypage.php?un=Oa348uty8&ps=op986hGTfreu Then when it gets to the PHP script decrypt it and encrypt it again with a different salt.
So when it leaves the application it would be encrypted but not the correct way, and then when it hits the PHP script server side decrypt it and re-encrypt it with the correct salt so it would correctly match the stored encrypted password.
This way, they user would not know what the encrypted version of their password is supposed to look like so without that they would not be able to tamper with the URL and try to insert fake values.
To put it in a nutshell, you are thinking of this:
On server side you have:
a database, with login/password matches.
a script that take 2 parameters (password and username) and check in the database if the couple exists
Your problem:
When your local application call the php script on server side, the 2 parameters are given in plain text. And you want to avoid tampering ( if your script are safe against injection i only see tampering used to bruteforce the auth <= keep in mind that i will keep this assumption in the whole post)
Your solution:
On client side, encrypt the 2 parameters
On server side, add a salt in your script to salt
Then decrypt the 2 parameters and encrypt with a salt
What I think:
This will not solve the tampering issue, someone can still forge requests.
The first encryption is useless because someone can retreive the key used by your client.
The second encryption is not safe enought because you use the same salt for all you users.
What I suggest:
Accept that tampering can't be avoided if you don't use a secure protocol like HTTPS (can either use SSL or TLS).
If you want an acceptable security without HTTPS the following is what i would implement:
A token system that you will check in order to see if the user can perform the login operation
A username that would not be encrypted
The password sha1 hashed stored in database
On client side, you call the script and provide the username as non encrypted and your password as a sha1 hash, rehashed with a random salt (sha1(sha1(pass)+salt) (the salt is stored in the user session on server side)
The script would then compared the provided hash with db password hash rehashed with session salt
The improvement is that the attacker must try to brute force two sha1 passwords consecutivaly and must provide a valid token to perform the login action. Plus if you use as salt a string using hex char of a variable even length, it will make the job harder for the attacker to recognised that the value bruteforced by the second hash is a sha1 hash, and even if he know it's an sha1 he will have to test multiple case to try to find the right portion of the value that correspond to the hash.
Because of variable salt, a same password won't be the same if hashed:
Imagine the attacker sniffed a hash and know which password was used then sniff another hash that was made with the same password as the other, the attacker won't be able to know that the 2 password where the same( a little overkill but still usefull).
It is safer to store the password as hashed value, because if the attacker manage to dump your user table, he won't be able to use the passwords right away, he would have to bruteforce each of then.
Finally sha1 hash are safer than md5 (i tell you that because you used the md5 tag in your post)
The downside of this method is that passwords can't be reversed, so you won't be able to given them back to your users if they lost it. You will have to make them set a new one.
An hardcore way (still without using HTTPS), would be to encrypt your password and username with a strong cypher (like AES or 3DES) and use a secure key echange algorythm (like the Diffie Hellman one) to exchange a random shared key.
This method won't block tampering, but will screw the attacker, because he won't be able to decrypt the value (assuming he only is sniffing the network). The key is random and never hardcoded in any of your application, so even if someone reverse your client, he won't be able to retreive a key.
I would still recommend to store your password value has hash.
An extreme way would be to merge the 2 methods but would be completly overkill.
Hope this will give you ideas
The problem with your approach isn't whether you are using encrpyted passwords and usernames in the URL or not. If the user authenticates by sending the encrpyted strings to you, then I as an attacker can still sniff out those hashes, pass them to your application and authenticate. This is unless then, that you do some public key/private key exchange before hand, but that is just reimplementing HTTPS, so you might as well just use HTTPS.
What you should do is to send the request using POST over HTTPS.
POST: So that the authentication details will not be in the URL and show up in logs and referrer URLs.
HTTPS so that the content of the whole request is fully encrypted and can only be decrypted by the client application and the server side.
encryption with Javascript from client to server only prevent from non SSL posting fails.
I think you must use sessions instead of this type encryption .
Update:
You could add your own secret key in both scripts.
For a login system in php would this be a suitable outline of how it would work:
users types in username and password, clicks login button.
Checks if user exists in database,
if it does, then retrieve the salt
for that user
hash the password and
salt (would this be done on the
client or server side? I think
client side would be better, but php
is server side so how would you do
this?)
check value against value in
database,
if the values match then
user has typed in correct password
and they are logged in.
Checks if user exists in database, if it does then retrieve the salt for that user hash the password and salt
No. This means you are hitting your database twice.
hash the password and salt (would this be done on the client or server side? I think client side would be better
No. The point of hashing the password is so that if someone compromises your database, they can't (easily) find out what they need to send to your system (or other systems) to log in as that user.
If you hash the password before sending it to the server, then the attacker can bypass the JS and send the prehashed password read from the database to your system.
User submits username and password
Password is hashed with the standard salt for the system
SELECT some,cols FROM your_users WHERE username=? and password=?
Count the number of rows returned from the database.
Checks if user exists in database, if it does then retrieve the salt for that user hash the password and salt (would this be done on the client or server side? I think client side would be better, but php is server side so how would you do this?)
The important thing to remember is that you never ever trust the user which means where authentication is concerned you should do as much as possible on the server side. Give the user as little information as possible and don't trust them with anything.
In regards to your question, the obvious point is that there is far more data transfer involved if you let the user precompute the hash. Rather than the single request and response there are 3 requests and responses required. It also increases the requirements from a browser to a browser with JavaScript enabled. Depending on your audience a lot of users can have JavaScript disabled (usually via the NoScript plugin).
Regarding security, while allowing the the user to see the salt wouldn't effect the defense against rainbow tables, showing them how you combine the salt and the password does.
Brute force attempts through the web interface are not that much of an issue anyway as hopefully you would only allow 5 (or so) login attempts per username per hour. Knowing the salt and hashing algorithm doesn't help at all (It just reduces your sever load ;) ). However if they have the database and know how to combine the salt and the hash it becomes that much easier to do a brute force attack.
While security through obscurity is no real defence, it does make your system that much harder to break, so I would reccomend that you don't attempt to do hashing on the client side.
It has to be Server Side
You are on the right track, but let me help you improve your system.
Generate a strong random key and store it in a file above your document root:
/home/username/key
/home/username/public_html/login.php
The file should contain (pseudo) random binary data with as much strength as possible. 512-bits of random data should be quite okay.
Then generate a unique salt for each user in your system. This salt does not have to be stronger than 16-bits of random binary data.
Finally, the password hashes should be something like:
hash('sha256', $password . $salt . $key);
where the hash algorithm matters a lot. Do not use MD5 or SHA-1. Use the SHA-2 family, typically SHA-256 or SHA-512. Also, Whirlpool is a good choice.
If you want to improve your system even more, you could iteratively hash again and again like:
public static function hash($algorithm, $data, $iterations = 1, $rawOutput = false)
{
if ($iterations < 1)
throw new Exception('There must be at least one iteration.');
while ($iterations--)
{
$data = hash($algorithm, $data, true);
}
return ($rawOutput ? (binary) $data : bin2hex($data));
}
Why such many moves?
Check if user exists in database, with given salted hashed password
if it does, then retrieve the user information
that's all
If you're talking of secure password transfer from client to the server - that's another story, you can refer to the HTTP digest authorization description for the schema. In short, it's client-side password hashing using random one-time token stored on the server side. OR SSL, of course
Most, if not all the form validation should be done on the server side. The users will be able to look at all client-side code and having any verification across a database done on the client-side will have massive security issues.
There might be different ways of approaching what you are trying to do. Here is what I would do:
Start a session if you want the user to be redirected somewhere and you need the username for that page
The general syntax for hashing in PHP is hash('nameOfHashFunction', $pswrd . $salt); you can cross verify this with the hash you have stored for the particular user.
The latest member of the SHA family is SHA-3, it was released in 2015. You can read more about it on its Wikipedia page. If there is a new member to the SHA family when you are reading this, I'd highly recommend you give it a light read and use that instead.
https://en.wikipedia.org/wiki/SHA-2
https://en.wikipedia.org/wiki/SHA-3