Storing Database Passwords in a Database - php

We are building a system that will have multiple separate client databases, clients are allowed to create as much as they want. There is an "Admin" database that holds the usernames, the database names, usernames and passwords for the databases on the server are all stored in an "admin" database. I use the information to connect to the database selected by the user, so I need to be able to be able to retrieve the actual password (I think... right?).
So what is the best way to go about storing the passwords and even the database names? Is there a way I can encrypt, then unencrypt when I need it?
Thanks in advance for any help..
Aloha,
James

If you want to encrypt the database name, you can use functions like AES_ENCRYPT()/AES_DECRYPT().
You NEVER store passwords in plain.
You NEVER store passwords in decryptable form.
You store the password using one-way encryption. To check a password, you encrypt the password the user gave you and compare it to what you stored.
For MySQL, you'd use the PASSWORD() function.

So here is the deal with storing passwords, which is really the most important part of all of this:
Plain text is a big no-no, because if your server is ever compromised, an attacker can release a list of all of your client's usernames and passwords, which is bad for all sorts of reasons.
Encrypted passwords are bad because if your server is ever compromised, an attacker can simply decrypt the passwords the same way as your program did, and now you have the same problem as plaintext.
Cryptographic digests like MD5, SHA-1, and even SHA-512 are a lot better because you only ever store and compare the hashed passwords, but they are still bad because they were designed to hash data very quickly for the purposes of data integrity and signing. This makes it surprisingly easy to reverse-engineer passwords via brute force attacks on modern hardware--even with salt! (See articles on leveraging GPUs for this purpose!)
So where does this leave us? It turns out that digests are a good way to go, but you want ones that are computationally complex so that brute force attacks are difficult. There are a number of these available, but I have adopted the Brcypt hash in my professional work.
As a side note, passwords should always be stored with salt to avoid rainbow table attacks. One advantage of Bcrypt is that is has the salting routines built into it, so that you don't have to worry about it.

I would second the NEVER store passwords in plain/decryptable form.
If you really need to access the users databases, you could use an admin/root with access to any user-database in the server.

Related

Store Usernames and passwords in encrypted file instead of database

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.

Encryption of hashed passwords?

I came about this security discussion after reading some topics about session management in php, have a look:
https://paragonie.com/blog/2015/04/secure-authentication-php-with-long-term-persistence#title.2
Quote from Chapter: To Pepper Or Not To Pepper?
A much better solution, which is especially useful if you employ hardware separation, is to encrypt the hashes before you insert them in your database. With this safeguard in place, even if an attacker finds a way to dump all of your database tables, they first have to decrypt the hashes before they can even begin to crack them. With the PHP and the database on separate hardware, this becomes much more secure.
In this article, the link to https://github.com/defuse/php-encryption is shared...
So far, I only used password_hash() in order to store passwords in a database. Is it recommendable to encrypt the hash itself? What's your opinion?
Thanks for your ideas!
Hashing with an appropriate hash algorithm is usually enough to protect the passwords, but it is indeed more secure to encrypt (not encode) the hashes afterwards.
When you encrypt the hashes with a server-side key, an attacker must gain additional privileges on the server, to get this key (without the key, the hashes are worthless). It is much easier to get readonly access to a database, than to get privileges on a server. Examples are SQL-injection, thrown away backups, discarded servers, ... In all this cases the encryption would protect the hashes.
In this answer you can find more information, or maybe you want to have a look at the end of my tutorial about safely storing passwords.
Is it recommendable to encode the hash itself? What's your opinion?
No, password_hash() / password_verify() is sufficient. People who need spinal-tap grade security can refer to that part of the article for guidance to avoid accidentally shooting themselves in the foot trying to improve their security, but in general if you're using bcrypt in 2016 then you're fine.
Unless you have separate servers for your website and for your database, the security gain by this strategy is zero. If I can get into your database, I can almost certainly get to your file system, and recover the encryption key.
If you do have separate hardware, and you use an authenticated encryption library such as the one provided by Defuse Security, do feel free to use it. Just know that it's not necessary for most use cases, as the password hashing API provides decent security against modern password cracking.
In a later version on PHP, they'll also support Argon2. If you're going to go overboard, switch to that instead of adding complexity to your protocol.
(Also, it's encrypt, not encode.)
there's no need at all to encrypt the hashes. The attacker has to reverse the hash to find the correct plaintext (user password). This is equivalent to find out the right key for the encryption. hashing is enough. plus salt obviously otherwise your schema is susceptible to rainbow table attacks

the best way to handle user's database name and passwords [duplicate]

I'm using Mysql and I was assuming it was better to separate out a users personal information and their login and password into two different tables and then just reference them between the two.
Note : To clarify my post, I understand the techniques of securing the password (hash, salt, etc). I just know that if I'm following practices from other parts of my life (investing, data backup, even personal storage) that in the worst case scenario (comprised table or fire) that having information split among tables provides the potential to protect your additional data.
Don't store passwords. If it's ever sitting on a disk, it can be stolen. Instead, store password hashes. Use the right hashing algorithm, like bcrypt (which includes a salt).
EDIT: The OP has responded that he understands the above issue.
There's no need to store the password in a physically different table from the login. If one database table is compromised, it's not a large leap to access another table in that same database.
If you're sufficiently concerned about security and security-in-depth, you might consider storing the user credentials in a completely separate data store from your domain data. One approach, commonly done, is to store credentials in an LDAP directory server. This might also help with any single-sign-on work you do later.
The passwords should be stored as a cryptographic hash, which is a non-reversible operation that prevents reading the plain text. When authenticating users, the password input is subjected to the same hashing process and the hashes compared.
Avoid the use of a fast and cheap hash such as MD5 or SHA1; the objective is to make it expensive for an attacker to compute rainbow tables (based on hash collisions); a fast hash counteracts this. Use of an expensive hash is not a problem for authentication scenarios, since it will have no effect on a single run of the hash.
In addition to hashing, salt the hash with a randomly generated value; a nonce, which is then stored in the database and concatenated with the data prior to hashing. This increases the number of possible combinations which have to be generated when computing collisions, and thus increases the overall time complexity of generating rainbow tables.
Your password hash column can be a fixed length; your cryptographic hash should output values which can be encoded into a fixed length, which will be the same for all hashes.
Wherever possible, avoid rolling your own password authentication mechanism; use an existing solution, such as bcrypt.
An excellent explanation of how to handle passwords, and what you need to concern yourself with, can be found at http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes.
As a final note, please remember that if an attacker obtains access to your database, then your immediate concern should probably be with any sensitive or personally-identifying information they may have access to, and any damage they may have done.
There's nothing wrong with putting them in the same table. In fact, it would be much faster, so I'd highly recommend it. I don't know why you'd want to split it up.
I'll attempt to answer your original question. Having it all in one table is fine unless you just have a lot of personal information to gather. In that case it may make sense to split it up. That decision should be made based on the amount of personal information you're dealing with and how often it needs to be accessed.
I'd say most of the time I'd do something like this in a single table:
UserID, FirstName, LastName, Email, Password, TempPassword
But... if you're gathering much more than that. Say you're gathering phone, fax, birth date, biography, etc, etc. And if most of that information is rarely accessed then I'd probably put that in its own table and connect it with a one-to-one relationship. After all, the fewer columns you have on a table, the faster your queries against that table will be. And sometimes it makes sense to simplify the tables that are most accessed. There is a performance hit with the JOIN though whenever you do need to access that personal information, so that's something you'll have to consider.
EDIT -- You know what, I just thought of something. If you create an index on the username or email field (whichever you prefer), it'll almost completely eliminate the performance drawback of creating so many columns in a user table. I say that because whenever you login the WHERE clause will actually be extremely quick to find the username if it has an index and it won't matter if you have 100 columns in that table. So I've changed my opinion. I'd put it all in one table. ;)
In either case, since security seems to be a popular topic, the password should be a hash value. I'd suggest SHA1 (or SHA256 if you're really concerned about it). TempPassword should also use a hash and it's only there for the forgot password functionality. Obviously with a hash you can't decrypt and send the user their original password. So instead you generate a temporary password they can login with, and then force them to change their password again after login.
Will all of this data always have a 1:1 relationship with the user? If you can forsee allowing users to have multiple addresses, phone numbers, etc, then you may want to break out the personal info into a separate table.
First, to state the (hopefully) obvious, if you can in any way at all avoid storing usernames and passwords do so; it's a big responsibility and if your credential store is breached it may provide access to many other places for the same users (due to password sharing).
If you must store credentials:
Don't store a reversible form; store a hash using a recognized algorithm like SHA-256. Use cryptographic software from a reputable trustworthy source - DO NOT ATTEMPT TO ROLL YOUR OWN, YOU WILL LIKELY GET IT WRONG.
For each credential set, store a salt along with the hashed data; this is used to "prime" the hash such that two identical passwords do not produce the same hash - since that gives away that the passwords are the same.
Use a secure random generator. Weak randomness is the number one cause of encryption related security failures, not cipher algorithms.
If you must store reversible credentials:
Choose a good encryption algorithm - AES-256, 3DES (dated), or a public key cipher. Use cryptographic software from a reputable trustworthy source - DO NOT ATTEMPT TO ROLL YOUR OWN, YOU WILL LIKELY GET IT WRONG.
For each credential set, store a salt (unencrypted) along with the encrypted data; this is used to "prime" the encryption cipher such that two identical passwords do not produce the same cipher text - since that gives away that the passwords are the same.
Use a secure random generator. Weak randomness is the number one cause of encryption related security failures, not cipher algorithms.
Store the encryption/decryption key(s) separately from your database, in an O/S secured file, accessible only to your applications runtime profile. That way, if your DB is breached (e.g. through SQL injection) your key is not automatically vulnerable, since that would require access to to the HDD in general. If your O/S supports file encryption tied to a profile, use it - it can only help and it's generally transparent (e.g. NTFS encryption).
If practical, store the keys themselves encrypted with a primary password. This usually means your app. will need that password keyed in at startup - it does no good to supply it in a parameter from a script since if your HDD is breached you must assume that both the key file and the script can be viewed.
If the username is not necessary to locate the account record encrypt both the username and password.
In my personal experience, storing the personal information and the login information in individual databases is the best practice in this case. The reason being should an SQL injection take place, it is limited (unless the infiltrator knows the inner layout of your database(s)) to the table that the data pertains to, as opposed to providing access to the whole conglomerate of data.
However, do note that this may come at the expense of needing to perform more queries, hence a performance hit.
You ought to store them in the same table, and use one-way encryption. MD5 will work, but is weak, so you might consider something like SHA1 or another method. There's no benefit to storing the 2 items in seperate tables.

What are the best practices to encrypt passwords stored in MySql using PhP?

I am seeking advice on how to securely store passwords in MySQL using PHP.
Overlooking the limitations of PHP itself, I want to know more about salting, hashing, and encrypting these bad boys.
Obviously people will continue to use weak passwords unless forced to do otherwise, but it's how I am storing them that is important to me. My user's passwords are far more important to me than the database itself, and as such I want to keep them in such a way that it will be painstaking and monotonous for any script kiddie trying reverse. Obviously with due diligence just about anything can be defeated, but I wouldn't mind making this particularly bothersome.
There are two scenarios we are looking at.
The kiddie has a complete copy of the database.
The kiddie has a complete copy of the PHP used to craft the password, and the database.
Any and all advice on this topic is graciously appreciated.
Use bcrypt. If someone has the user table of your database, then they can use brute force/rainbow tables/etc to their heart's content. Even with salt, if you're using MD5 or some other fast-hashing algorithm (which aren't designed to solve this problem, by the way); it's just a matter of time before it can be cracked.
Any well-known and widely-supported hashing algorithm is going to have this same basic "flaw" (if you can call it that; it's really by definition). The difference is that bcrypt is slow as molasses when performing the hashing operation, rendering a brute force attack much less effective.
For an absolutely great discussion on the merits of bcrypt, the dangers of other approaches, and the difficulty of password security in general, read this thread. It has lots of comments by many people that are much more knowledgeable about this sort of thing than I am, and it should hopefully help you understand more of the issues at stake.
Assuming you're using username and password as authentication tokens you can safely store the following to ensure the data can't be compromised.
Username (in plaintext)
Salt (random string)
Salted Hash (sha1(username + salt + password))
Using the scheme, an attacker cannot use rainbow tables against you and the passwords are not recoverable by any (reasonable) means. (That is, as long as your attacker isn't the government)
Even though the attacker has the salt and hash pairs it's not possible to use rainbow tables because all the possible hashes will need to be computed anyway, using the salt that they've been given, so it's a brand new brute force attack for each user.
Even with the source code and attacker won't be able to get hold of the passwords because the strength/security is in the hashing algorithm, not your code.
Combine this with using bcrypt as per Donut's answer and you're really quite safe. That is:
Username (in plaintext)
Salt (random string)
Salted Hash (bcrypt(username + salt + password))
Taking advice from here, for added fun you can dynamically change your salt as well. For example, use different salts for usernames of different length, use the user's registration date as the salt. This makes it that even if someone DOES get to your database, they can't just re-generate the hash, they have to calculate a hash table for each salt that you used.
If your users are over the internet, OpenId would be one of your best options. http://openid.net/
If your users are on your network, can you do Integrated Security?
In other words.. do not store their passwords.
Usually "salted" passwords (like with bcrypt) mean that not the password itself is stored, but only something like
salt
hash(salt with password appended)
Now if the kiddie has your database (and of course, the code - there is no point in keeping the code secret), he/she can only guess passwords, calculate the salted hash, and compare. If the hash function is expensive (like bcrypt is), than guessing is expensive too.
It's simple
store(sha256("somesalt" + password));
And nobody will be able to reverse it :)
See also: https://stackoverflow.com/questions/3897434/password-security-sha1-sha256-or-sha512

How to best store user information and user login and password

I'm using Mysql and I was assuming it was better to separate out a users personal information and their login and password into two different tables and then just reference them between the two.
Note : To clarify my post, I understand the techniques of securing the password (hash, salt, etc). I just know that if I'm following practices from other parts of my life (investing, data backup, even personal storage) that in the worst case scenario (comprised table or fire) that having information split among tables provides the potential to protect your additional data.
Don't store passwords. If it's ever sitting on a disk, it can be stolen. Instead, store password hashes. Use the right hashing algorithm, like bcrypt (which includes a salt).
EDIT: The OP has responded that he understands the above issue.
There's no need to store the password in a physically different table from the login. If one database table is compromised, it's not a large leap to access another table in that same database.
If you're sufficiently concerned about security and security-in-depth, you might consider storing the user credentials in a completely separate data store from your domain data. One approach, commonly done, is to store credentials in an LDAP directory server. This might also help with any single-sign-on work you do later.
The passwords should be stored as a cryptographic hash, which is a non-reversible operation that prevents reading the plain text. When authenticating users, the password input is subjected to the same hashing process and the hashes compared.
Avoid the use of a fast and cheap hash such as MD5 or SHA1; the objective is to make it expensive for an attacker to compute rainbow tables (based on hash collisions); a fast hash counteracts this. Use of an expensive hash is not a problem for authentication scenarios, since it will have no effect on a single run of the hash.
In addition to hashing, salt the hash with a randomly generated value; a nonce, which is then stored in the database and concatenated with the data prior to hashing. This increases the number of possible combinations which have to be generated when computing collisions, and thus increases the overall time complexity of generating rainbow tables.
Your password hash column can be a fixed length; your cryptographic hash should output values which can be encoded into a fixed length, which will be the same for all hashes.
Wherever possible, avoid rolling your own password authentication mechanism; use an existing solution, such as bcrypt.
An excellent explanation of how to handle passwords, and what you need to concern yourself with, can be found at http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes.
As a final note, please remember that if an attacker obtains access to your database, then your immediate concern should probably be with any sensitive or personally-identifying information they may have access to, and any damage they may have done.
There's nothing wrong with putting them in the same table. In fact, it would be much faster, so I'd highly recommend it. I don't know why you'd want to split it up.
I'll attempt to answer your original question. Having it all in one table is fine unless you just have a lot of personal information to gather. In that case it may make sense to split it up. That decision should be made based on the amount of personal information you're dealing with and how often it needs to be accessed.
I'd say most of the time I'd do something like this in a single table:
UserID, FirstName, LastName, Email, Password, TempPassword
But... if you're gathering much more than that. Say you're gathering phone, fax, birth date, biography, etc, etc. And if most of that information is rarely accessed then I'd probably put that in its own table and connect it with a one-to-one relationship. After all, the fewer columns you have on a table, the faster your queries against that table will be. And sometimes it makes sense to simplify the tables that are most accessed. There is a performance hit with the JOIN though whenever you do need to access that personal information, so that's something you'll have to consider.
EDIT -- You know what, I just thought of something. If you create an index on the username or email field (whichever you prefer), it'll almost completely eliminate the performance drawback of creating so many columns in a user table. I say that because whenever you login the WHERE clause will actually be extremely quick to find the username if it has an index and it won't matter if you have 100 columns in that table. So I've changed my opinion. I'd put it all in one table. ;)
In either case, since security seems to be a popular topic, the password should be a hash value. I'd suggest SHA1 (or SHA256 if you're really concerned about it). TempPassword should also use a hash and it's only there for the forgot password functionality. Obviously with a hash you can't decrypt and send the user their original password. So instead you generate a temporary password they can login with, and then force them to change their password again after login.
Will all of this data always have a 1:1 relationship with the user? If you can forsee allowing users to have multiple addresses, phone numbers, etc, then you may want to break out the personal info into a separate table.
First, to state the (hopefully) obvious, if you can in any way at all avoid storing usernames and passwords do so; it's a big responsibility and if your credential store is breached it may provide access to many other places for the same users (due to password sharing).
If you must store credentials:
Don't store a reversible form; store a hash using a recognized algorithm like SHA-256. Use cryptographic software from a reputable trustworthy source - DO NOT ATTEMPT TO ROLL YOUR OWN, YOU WILL LIKELY GET IT WRONG.
For each credential set, store a salt along with the hashed data; this is used to "prime" the hash such that two identical passwords do not produce the same hash - since that gives away that the passwords are the same.
Use a secure random generator. Weak randomness is the number one cause of encryption related security failures, not cipher algorithms.
If you must store reversible credentials:
Choose a good encryption algorithm - AES-256, 3DES (dated), or a public key cipher. Use cryptographic software from a reputable trustworthy source - DO NOT ATTEMPT TO ROLL YOUR OWN, YOU WILL LIKELY GET IT WRONG.
For each credential set, store a salt (unencrypted) along with the encrypted data; this is used to "prime" the encryption cipher such that two identical passwords do not produce the same cipher text - since that gives away that the passwords are the same.
Use a secure random generator. Weak randomness is the number one cause of encryption related security failures, not cipher algorithms.
Store the encryption/decryption key(s) separately from your database, in an O/S secured file, accessible only to your applications runtime profile. That way, if your DB is breached (e.g. through SQL injection) your key is not automatically vulnerable, since that would require access to to the HDD in general. If your O/S supports file encryption tied to a profile, use it - it can only help and it's generally transparent (e.g. NTFS encryption).
If practical, store the keys themselves encrypted with a primary password. This usually means your app. will need that password keyed in at startup - it does no good to supply it in a parameter from a script since if your HDD is breached you must assume that both the key file and the script can be viewed.
If the username is not necessary to locate the account record encrypt both the username and password.
In my personal experience, storing the personal information and the login information in individual databases is the best practice in this case. The reason being should an SQL injection take place, it is limited (unless the infiltrator knows the inner layout of your database(s)) to the table that the data pertains to, as opposed to providing access to the whole conglomerate of data.
However, do note that this may come at the expense of needing to perform more queries, hence a performance hit.
You ought to store them in the same table, and use one-way encryption. MD5 will work, but is weak, so you might consider something like SHA1 or another method. There's no benefit to storing the 2 items in seperate tables.

Categories