I am working on a website to learn more about web programming and also to launch same as a start-up. The first problem that i came across was how to implement a secure login system. Currently i have take steps like escaping the password and then hashing it, using a salt. But i was wondering is the following mechanism secure,
I will make the user enter username and will keep checking if the user has entered his username (when textbox loses focus or a button for submitting username, also to prevent listing of usernames ill block the user by setting cookie on system if multiple incorrect attempts are made, or maybe ill use captcha for each ), once entered username, ill send back random stored salt to user.
Using that salt and password entered, user will hash the password and send it in form
I'll verify the password by comparing hashes
I think it will be beneficial since server side i don't have to do any processing, and hence i don't have to worry about DoS attack, as i read somewhere that using some slow hashing like BCrypt will expose site to DoS attacks.
Also user's password is never communicated over the network, making it secure from person sniffing the network.
Please do point me to some reference or anything that may help me to implement securely. Consider me noob because i have still started learning, and would like to know what you think of it, what possible flaws are there ? and what must be secure strategy.
UPDATE-
Many answers i am getting, all usually assume that i am thinking this as an alternative to SSL; no it's not the case. By protection against sniffing i meant protection just in case some attacker might make the user use a SSL proxy.
just for reference - https://security.stackexchange.com/questions/19616/why-is-it-possible-to-sniff-an-https-ssl-request
Client side hashing can have its advantages, but you cannot do without server side hashing. In your scenario, the calculated hash acts as the new password. An attacker with read access to the database (SQL-injection) will see this hash and can use it directly as password to login.
Using a slow hash with a cost factor is mandatory, usually it is done server-side, because client-side languages are slower and can do less rounds. Of course somebody can use it to make a DoS attack, but this can be done with every other page as well. The size of the password doesn't matter (as one can read ocassionally), because after the first round only the hash will be hashed.
If you plan to do a client-side hashing, don't forget to calculate a (fast) hash on the server as well. And you have to ensure, that the hashing was done correctly client-side. Much more important is, that you use SSL to send the credentials.
The question Secure authentication: partial client-side key stretching… could be of interest to you.
EDIT:
I will try to sum up the important points for client-side hashing.
A slow hashing algorithm with a salt and a cost factor (BCrypt/PBKDF2/SCrypt) is mandataory, this is the only thing that makes it hard to retrieve the original password from a hash, if the password is weak. It is possible to do this client-side.
Server-side hashing is mandatory too, to prevent an attacker from using stored hashes directly as passwords, if he knows them. The hash can be fast without a salt (SHA-256), because the input (BCrypt hash) has enough entropy. Such a strong "password" with 60 characters cannot be successfully brute-forced.
If the attacker cannot crack the fast SHA-256 hash because the input is too strong, he can try to brute-force with the original passwords (from a dictionary). But to do this he would first have to calculate the slow BCrypt hash and afterwards the fast SHA-256 hash.
Client-side languages like JavaScript are usually interpreted and much slower than compiled code, so you can do less rounds in the same time as you could do on the server (this weakens security). If you have the possibility to run native code on the client, there is no disadvantage to do the slow hash client side.
no, you should not send any 'salt' to the user.
It can be sniffed.
What you're basically doing is a send something like a (csrf-)token that can be used once. Nothing wrong with that, but you seem to be re-inventing the wheel.
Seriously, I think your solution is good only for hackers. If I sniff communication I will get gradually username, salt and password hash. You have to send all those values over the network (username to get salt, password hash to auth attempt). Now I can use sniffed password hash directly in malicious login request or start cracking password locally (users usually have same password for more services). All checks and limits on auth attempts are out of game because I don't need send request to guess password. Depends on hash algorithm it will more or less time consumption. I think network sniffing is the main purpose why you calculate with not sending plain password over the network.
You can secure your network communication with TLS but then all things with sending salt and hashing password on client are unneccessary. You can just send password in plain text to server. But yes, hashing password on client, why not if you want. You can use ie. sha1 also on server if you think that bcrypt is performance issue and possibly DOS cause.
Good example of protocol that is used for transmitting infomation through unsecure network is OAuth 1.0a and even in it you need some cryptography or TLS for transfering consumer secret.
Let me know if I am something understood incorrectly.
I guess only drawback i can see is using this on low-end mobile devices.
Related
I am currently working on a better login-routine for one of my websites and I wanted to adress securely transmitting login-Data to the server. There are several articles and posts concerning this topic, but they frequently have quite different opinions on how it has to be done.
Starting off with SSL, pretty everyone is on the same page here: You should use SSL, and I do. Then there are those who say: "That is enough, with SSL you can send username & PW as plaintext". I disagree. Other say that it should still be hashed. And I read several posts where I had the feeling that people were concerned about different aspects of a login routine and proposed mechanisms to only handle their security aspect.
So what I want to know, if the routine I have so far elaborated would be adequate, too much or too little. I will try to explain why I chose to implement a certain feature and which security aspect I try to cover:
SSL:
The communication between server and client should always be https:// - nevertheless I read several articles warning that SSL is "no silver bullet", but it is a good start.
Hash PW clientside (SHA3, ARGON2i, BCRYPT):
Many comments did reject hasing PW. Using a hash, comparing it to a HASHed PW in the database would simply change the PW from the userinput to the HASH - an attacker would still have access by simply getting hands on the HASH. I agree. BUT (this is what I meant that people read about different aspects of security) the ones claiming that it is better than sending plaintext because in that case ONLY your system, but not other systems with the same PW would be compromised (unless, of course they use also hashed PWs). So I would implement HASHing of the password before sending it via SSL.
encrypting the HASH:
Let's assume SSL could not hide the data we send to the server and an attacker would read the HASHed PW. The only way that I could think of to adjust the security to this scenario, would be to encrypt (e.g. AES CBC) the client-side HASHed PW with a key that has been send beforehand by the server, and that has a short expiration period. The key would have to be generated randomly. Like that, the server can decrypt the data, and then compare the HASH with the one it its database.
To sum it up:
-> Clients wants to Login via SSL -> Server sends back a key -> Clientside hashing of the PW -> clientside encryption of teh HASH with the key and a random IV -> Server decrypts the data with the key (stored in $_SESSION, with an expiration timestamp) and compares the HASH with the HASH in his DB (if the expiration timestamp is still valid).
Would this be a good approach? Or is this too much? (Can there be too much security?) Or do you have any alternative solutions?
Or is this too much? (Can there be too much security?)
You're talking about it like security is a liquid that must fill-up a container without overflowing it. That's not how it works and you're asking the wrong questions, which means you're trying to solve the wrong problem. It has nothing to do with the amount of measures that you pile up, but whether and how they address a specific problem.
If the problem is protecting data in transit, then the solution is TLS (SSL) - that's what it is specifically designed for, and anything that you can come up with would, in the very best case scenario, be a poor alternative to it. You can't outsmart the decades of research and practice that has gone into TLS.
That was already answered by Jay Blanchard though ... I want to point out the mistakes you've made, because otherwise it looks like one man's word vs. another (and you may listen, but other readers might not):
SSL:
The communication between server and client should always be https:// - nevertheless I read several articles warning that SSL is "no silver bullet", but it is a good start.
It is both a silver bullet and not a silver bullet, depending on how you look at it.
When we talk about protecting data in transit, it is THE solution - a silver bullet in a way.
But that doesn't mean flaws won't be found in time, or that you just switch it On and say "I have TLS, I am secure!" - no, it still requires proper configuration, maintenance and adjustments over time. In that sense, it's not a silver bullet.
It also doesn't solve many other security issues, so when someone asks "How do I make my application secure?", of course you would say that it is not a silver bullet - many threats need to be separately addressed and there's no one-stop shop for them all.
Hash PW clientside (SHA3, ARGON2i, BCRYPT):
Many comments did reject hasing PW. Using a hash, comparing it to a HASHed PW in the database would simply change the PW from the userinput to the HASH - an attacker would still have access by simply getting hands on the HASH. I agree. BUT (this is what I meant that people read about different aspects of security) the ones claiming that it is better than sending plaintext because in that case ONLY your system, but not other systems with the same PW would be compromised (unless, of course they use also hashed PWs). So I would implement HASHing of the password before sending it via SSL.
It's the exact opposite - when you hash the password on the client side, that only makes accounts on your site easier to compromise after a data breach.
Lookup the hash in the database - got the password right there, that's the part you figured out. But that hash is still the result of a certain user-provided string ... Nothing stops an attacker from applying the same techniques to break the hash in order to compromise accounts on other servers.
So, this doesn't in any way solve the problem, but you'll probably think that in the worst case it doesn't do anything bad ... Well, indirectly it does - you have to make a considerable effort, to implement something with a lot of potential for mistakes.
In the best case scenario, you're just wasting your time, but a minor mistake can be a major vulnerability.
Also, SHA-3 is a cryptographic primitive - it has many appliances, but mostly as a building block. You can't just put one round of it on a password and be happy with the resulting hash.
For a comparison, bcrypt uses Blowfish internally (as a primitive of the same kind as SHA-3), but you cannot equate Blowfish to bcrypt.
encrypting the HASH:
Let's assume SSL could not hide the data we send to the server and an attacker would read the HASHed PW. The only way that I could think of to adjust the security to this scenario, would be to encrypt (e.g. AES CBC) the client-side HASHed PW with a key that has been send beforehand by the server, and that has a short expiration period. The key would have to be generated randomly. Like that, the server can decrypt the data, and then compare the HASH with the one it its database.
There are valid reasons to encrypt password hashes, but not for this purpose and certainly not on the client side.
You need a secure key-exchange protocol for this to even work. And guess how you do that? TLS.
There's literally nothing different between communicating an encryption key or a password over the wire. So, even if this was somehow a solution to protecting a password, how would you apply it again on the key itself? It makes no sense.
SSL is just fine, I have no idea why you disagree. Client-side hashing still leaves the PW visible on the client-side as well as the hash, so nothing gained there.
The question comes down to, "what are you protecting?" My guess is that you're not guarding anything needing more security than banks, and probably way less than that.
You're spending a lot of time trying to re-invent the wheel here, rather than relying on tried and true methods. Stick with what is proven.
-> Clients wants to Login via SSL -> Server sends back a key -> Clientside hashing of the PW -> clientside encryption of teh HASH with the key and a random IV -> Server decrypts the data with the key (stored in $_SESSION, with an expiration timestamp) and compares the HASH with the HASH in his DB (if the expiration timestamp is still valid).
Why encrypt a hash? That implies that the hash isn't secure enough. OK, fine, let's go with that. So let's assume an attacker is able to read the hash, and that's the reason you want to protect it with an additional layer. If an attacker is in a position to read the hash, they're also in a position to read the key sent by the server to the client, and the Javascript which contains the encryption algorithm (assuming you're talking about an HTML scenario here). Now the attacker has everything to replicate and reverse the encryption, and in fact they are probably also in a position to alter the Javascript sent from the server to the client in the first place.
To protect against that happening, you'd need some wrapper that protects all the communication between the client and the server, like, oh, uhm, say… SSL.
Since SSL already protects the communication from 3rd party interference… what do you think you're adding with that additional song and dance exactly? I'll tell you: nothing.
In many basic PHP user logins, a password_hash is used to hash the password for database storage. I get the process of hashing, how to use password_hash, and why this is being done but what I don't understand is how this actually protects the password? I feel as if I might be missing something.
Correct me if I'm wrong but PHP is almost exclusively ran on the server side. Doesn't this mean that the plain password is being sent and then hashed when it reaches the server? Wouldn't this allow for others to pick out the password in transport?
My apologies if this has been asked before. I've tried to do a search prior to asking this but all hits came up as the actual mechanics of password_hash.
Yes, password_hash does hashing serverside. Network sniffing would allow the password to be recovered—but you could get into an account by sniffing unencrypted traffic easily anyway.
What password hashing intends to do is protect a user's password in the event of a database breach/dump, preventing users' passwords from being harvested (easily—they can still be brute-forced with a lot of time and effort). It doesn't protect the password in-transit, that's what HTTPS is for. Whereas hashing protects once the password makes it to the server, HTTPS ensures that only the intended recipient of the message (in this case, the server) can read the contents and ensure it hasn't been tampered with.
Password hashing is there to protect users from themselves. A lot of users use common passwords or continually reuse the same password for many sites. Password hashing is there, again, to protect users' passwords behind a one-way mathematical function which should at the very least slow down any potential attackers by making the plain text password unavailable.
You never send a password over the internet that isn't protected by an SSL cert. That way, the password is protected in transit until it gets to the endpoint and decrypted on the server.
This process is invisible to developers as long as the security certificate is in place and functioning correctly. That's not to say there are not other risks but that mitigates most of it.
So i know you are going to say this is bad, but i really dont like using a database as it is confusing and hard at the same time. I also think storing usernames and passwords in a file is bad, but both the username and password would be encrypted using md5. I dont think this is secure enough though though because im going to make it public. If you could give me tips on how to make this better please tell me.
Also You will only have two attempts per minute ;)
Here is my idea: https://drive.google.com/file/d/0B19YDO3uT0ClaVZsYjRFRVZkUzA/view?usp=sharing
Also if you could give me examples on how and where to store the file in the webserver? i am not very good with php to be honest
Most databases can be accessed from the open web and you have to store the database password in a PHP file as well. Therefore in most configurations there is no security benefit using a database. It is just a more comfortable handling.
Hashing passwords is always a good idea and should be taken for granted. md5 is not a secure algorithm. Consider usage of password_hash() instead. Don't forget to intersperse a salt string to prevent rainbow table attacs when your hashfile gets stolen.
Any two-way-encryption would make your system insecure at all, because you would have to hold the secrets for decryption into plain text on the server an an attacker could steal everything he needs.
Limiting the login attemps is certainly not a bad idea, however, it is not as essential as you think. The main weak point is to get read access to the hashfile and then process an offline bruteforce, preferably with rainbow tables.
Here's what I would suggest. Don't use md5 because it's insecure and too fast without using iterations.
You really must have an SSL certificate for this to be secure from people seeing the password. Anything without a certificate is roughly equivalent to the user sending a raw text password. You have basically just changed what their password is.
As zaph noted, it's best practice to pin the certificate
On the client
send the password to the web server (encrypted by the certificate for you)
On the web server
Store a salt (a unique random string)
Hash the password using bcrypt or another secure hashing algorithm that also takes the salt
Store the salt and the hashed salted password
You need to use a password hashing algorithm that also takes a salt and iterates such that the hashing takes substantial time such as 100ms. Typically you can use algorithms such as PDKDF2, bcrypt, script or password_hash.
The password must be hashed on the server.
Use HTTPS for communication the password and pin the server certificate in the app, the pinning is important as it will protect against MITM attacks.
A DB may not be necessary, it is an issue of lookup time and disk I/O. You can start with a flat fine and migrate to a DB if/when the performance is needed. "Uncle Bob" Martin delayed using a DB in FitNesse and in the end found a flat-file solution was all that was needed.
Note: Essentially all simple hash methods such as SHA2, SHA3, etc. are to fast and need many iterations to increase the calculation time. The time is important so an attacker can not try hashed quickly. A random (not exactly unique) salt per password is needed to eliminate the use of rainbow tables of pre-calculated hashes.
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 thought of an authentication system without SSL that seems reasonably secure. Am I overlooking something important?
User hits the login page
Server generates a salt for transmission (t-salt) and stores it in the session
Server sends the t-salt to the user as part of the login page that loads
User types in their username and password and clicks submit
Browser MD5 encrypts their password along with the t-salt
Browser sends username and MD5 (password + t-salt) to the server
Server retrieves password from database using username (*) Note below
Server MD5 encrypts password retrieved from step 7 along with the t-salt that was stored in the session in step 2
Server compares both of the MD5s from step 6 and step 8
If they are identical, the login is successfully authenticated
The server removes the t-salt from the session (added in step 2) to prevent potential replay attacks
* Note that the password retrieved in step 7 cannot be 1-way encrypted (as is common practice) in order for step 8 to work. But 2-way encryption systems can still be used to secure passwords at the database level. (Hey, that comes with the side benefit of allowing a more user friendly password recovery process.)
Aside from my note immediately above, what are the strengths and weaknesses of this scheme?
This'd be wide-open to man-in-the-middle attacks. Nothing would stop an attacker from sniffing the link and getting the salt as it goes from server->client or the hashed password as it goes from client->server, and replaying either.
Invalidating and generating a new salt after each attempt would prevent simple replays, but then it comes down to a race condition - can the attack submit their login attempt before the user? Even then, since the attacker's sitting in the middle, they could presumably interrupt the user's link, capture the salted password, and submit it themselves and capture the session.
You send the t-salt and the hashing algorythm. It wouldn't take long to calculate the password inside the hash.
You should reconsider SSL in my opinion.
While I think that your intentions are good, the fact of the matter is that there really is no security offered at all in your approach. As others have pointed out, any reasonably competent hacker will be able to intercept data going over the wire and execute a replay attack. That is not to mention the fact that any data going over the wire will be unencrypted, which exposes your users' potentially sensitive information to anyone.
The problem with this is that you're making the assumption that SSL is purely about encryption. Take a look at SSL is not about encryption. On this basis, your scheme falls apart at step 1 because you have no assurance that when the login page is loaded it has actually come from the site you think it has and that it hasn't been tampered with.
There are many precedents of this happening, the Tunisian government harvesting usernames and passwords is a good one and you'd be wide open to this style of attack as your login page could be altered before it even hits the browser.
Then of course you have the Firesheep problem in that your auth persistence (which I assume you do via cookies), is going backwards and forwards across an unencrypted network. It doesn't matter what you encrypt inside these cookies, if someone is able to grab it and reissue a request (very easily done at a public wifi hotspot), then you've got a session hijacking problem.
Then there's also the known weaknesses in MD5 but even using a more secure hashing algorithm won't save you from the other problems described above. Spend a tiny bit of money, do some minimal configuration and make SSL part of your login process. Refer to the OWASP Top 10 on Insufficient Transport Layer Security for more info.
Finally, SSL is not intended to be a panacea; it won't protect you from key loggers, it won't protect you from having your database breached and it won't protect you from someone whacking your end users over the head with a wrench until they disclose their password. But it's not meant to do any of these things, it's simply intended to be one more layer of defence - albeit an essential one - which is part of a broader security strategy.
One thing to think about is that SSL doesn't just provide confidentiality and integrity protection to the overall data stream (via encryption) it also provides a level of validation of the identity of the server.
In your example there's no way (that I can see) for the client to validate that they are speaking to the real server before providing their password, as such a DNS spoofing attack or some other MITM attack would be effective.
Also as mentioned, it would be possible to brute-force a users password quite easily as the attacker can intercept the salt going from server-->client and then the hashed password coming back. MD5 being a fast hash algorithm it would likely be quite an effective attack against standard user passwords.
The data transmitted while authenticated won't be secure, and implementing your own schemes is usually a pretty bad idea.