How to Secure Database Passwords in PHP

How to secure database passwords in PHP?

Several people misread this as a question about how to store passwords in a database. That is wrong. It is about how to store the password that lets you get to the database.

The usual solution is to move the password out of source-code into a configuration file. Then leave administration and securing that configuration file up to your system administrators. That way developers do not need to know anything about the production passwords, and there is no record of the password in your source-control.

How to store password securely in database

You hope to store your cisco switch passwords in your database in a form where you can recover the password plain text to use it for ssh connections.

Even if you encrypt the passwords in the database, your program that accesses the database will have to be able to decrypt them to use them. So the decryption key necessarily will be available to your program. That's entirely different from the kind of password-hashing mechanism available in php. Password hashing doesn't allow you to recover the password from the hash, only to compare a user-presented password with the hashed password to see if they match.

Storing decryptable passwords is not secure, and can never be secure. If somebody cracks your server, they then have access to your entire infrastructure. (Cybercreeps with access to switches and routers can really make a mess.) This is the kind of thing that shows up in https://KrebsOnSecurity.com . Don't do it. Please.

If you want more-or-less automated access to your switches via ssh, your best bet is to use ssh's key management features. The machine from which you access the switches will have a private key, and each switch will have a public key corresponding to the private key. If you configure the public keys correctly you can restrict the operations available to users who present the corresponding public keys. It's a big topic, too big for a Stack Overflow answer.

As usual, Digital Ocean's writeup of this topic is useful. https://www.digitalocean.com/community/tutorials/how-to-configure-ssh-key-based-authentication-on-a-linux-server

Protecting database password in a PHP file?

If I were you (and if I'm understanding your problem correctly) I would use an htaccess file. Basically, you will create two files in the directory you want to protect. The first, you will name .htaccess. That's all you need in the file name. Open the file in an editing program (e.g: Notepad++) and insert the following code:

    AuthType Basic  
AuthName "restricted area"
AuthUserFile "the/path/to/the/directory/you/are/in/.htpasswd"
require valid-user

The .htpasswd you see is the file name of the second file you will create. Create that file (with the name .htpasswd), and open it to edit it. In that file, type in the username of the person who is to enter the directory.

    JohnDoe

Followed by a colon.

    JohnDoe:

Now, go to a website like http://www.htaccesstools.com/htpasswd-generator/ and type in the Username (just put in "test") and password you want in the fields provided. Submit the information.

After you do that, it will pop up with a formatted line of information. Copy the mess of letters after the colon and paste them after the colon in your .htpasswd file. Save your work.

    JohnDoe:$apr1$eBsB98Mg$93ckYxSmT5BBfPqOS5a/6.

Now that you have done all that, when someone goes to the directory on your website, they will be prompted to give the username and password. If they know it, it will let them in, and then display what is in your PHP file (you will need to make sure the file is named index.php.

I hope that helps!

Securing DB password in php

Put the password in a separate PHP file, containing all your app settings, and include it at the top of the page. This file can then be kept out of Version Control, and replaced for each deployment.

Make sure that you keep the config.php file (or whatever you choose to name it) out of your root directory, also, so that it can't be accidentally served up to any users of your app. Also, as a further precaution, make sure that you give it the .php extension, so that if it somehow does still get served up, it should be parsed by PHP first, and any useful information (hopefully) removed - a common practice would be to name it with a .conf.php or .inc.php extension for this reason.

As for the Dev Environment, we use a single database shared by all the devs. It was originally created from live client data, cloned into our database, with certain information redacted / replaced for privacy reasons. The same database is used in our development build as well as our localhost builds.

Secure storage of database credentials

Simply place info.php outside your webroot. This way, you can include it, but should your web hosting f*#$ up, no one else can view that file, even as plain text.

You would then include it like this:

include('../info.php');

This way, even if someone finds out that you have a file called info.php that stores all your passwords, they cannot point their browser to that file.

The above would be the ideal and most watertight solution. However, if that is not possible due to permissions, the other option would be to place all sensitive files in a directory and block direct access to that directory using a .htaccess file.

In the directory you want to block off access to, place an .htaccess file with the following contents:

deny from all

Where to safely store database credentials within a PHP website

Common practices for this problem include putting the database credentials in a configuration file that is not PHP, such as a .ini file, and then reading that with PHP. To add extra security you should also put the configuration file outside of the web root, so that you can be sure no one can access the file by navigating directly to it.

For example, the Laravel framework (among others) define the web root in the /public directory, while outside that directory is a .env file containing database credentials among other settings.

Have a look here for more info: How to secure database passwords in PHP?

More importantly though, you should never have to worry about your PHP being served as plain text. Take the proper development precautions to ensure this never happens. Some starting points are:

  • Making sure you have PHP installed!
  • Make sure you open and close your tags properly
  • Make sure your file extension is .php and not .html (unless you use this work around)
  • Also make sure in production code that you aren't displaying errors on the page (display_errors ini)

PHP Mysql secure passwords

I know this is asked a lot, but right now (April 2016), what is the preferred method of storing passwords securely for my users? My data is not super-sensitive (it's just a game with no personal or financial details, but it would still be nice to have secure passwords).

I maintain the blog post that James Patterson linked to in his answer. Despite being a mere two months old, it's already due for a massive update, but that's being held back by the slow movement of several other languages. I can provide you with an immediate updated answer for PHP.

I'm going to answer in this format:

  1. What you should do today (i.e. the standard response) and why.
  2. What you should do later this year.
  3. What you should do in the years to come.

How to Safely Store a Password in 2016

As the blog post mentioned in the current iteration of the PHP password storage section, you want bcrypt, facilitated through PHP's built-in password API. This API is straightforward, but there are a few gotchas you need to keep in mind:

Hashing a password with bcrypt

$hash = password_hash($userPassword, PASSWORD_DEFAULT);

Validating a password with bcrypt

if (password_verify($userPassword, $hash)) {
// Login successful.
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
// Recalculate a new password_hash() and overwrite the one we stored previously
}
}

Why bcrypt?

Bcrypt is the preferred algorithm right now for many reasons:

  • Great GPU resistance (which matters a lot in resisting password cracking)
  • Well-studied by experts for many years -- it's the conservative choice
  • In low memory configurations, it's safer than scrypt.

Why not bcrypt?

There are two known weaknesses with bcrypt that you should be aware of:

  1. Bcrypt truncates after 72 characters.
  2. Bcrypt truncates after \0 bytes.

Typically, people run into the second problem while trying to solve the first problem. A good stop-gap solution for right now is:

Today's Recommendation: Bcrypt-SHA-384 (with base64 encoding)

/**
* Bcrypt-SHA-384 Verification
*
* @ref http://stackoverflow.com/a/36638120/2224584
* @param string $plaintext
* @param string $Hash
* @return bool
*/
function bcrypt_sha384_verify(string $plaintext, string $hash): bool
{
$prehash = \base64_encode(
\hash('sha384', $plaintext, true)
);
return \password_verify($prehash, $hash);
}

/**
* Creates a Bcrypt-SHA-384 hash
*
* @ref http://stackoverflow.com/a/36638120/2224584
* @param string $plaintext
* @param int $cost
* @return string
*/
function bcrypt_sha384_hash(string $plaintext, int $cost = 12): string
{
$prehash = \base64_encode(
\hash('sha384', $plaintext, true)
);
return \password_hash(
$prehash,
PASSWORD_BCRYPT,
['cost' => $cost]
);
}

The specific reasoning was all covered in How to Safely Store Your Users' Passwords in 2016.

How to Safely Store a Password in the Immediate Future

Later this year, you might consider switching to Argon2, the winner of the Password Hashing Competition. (It's not mandatory; bcrypt is still quite good. But in the coming years Argon2 will be the recommended algorithm, barring any new attacks against it.)

You can, in fact, use it right now. You just need to install libsodium 1.0.9 and libsodium-php 1.0.3 (or newer).

Hashing a password with Argon2i in PHP using libsodium

$hash = \Sodium\crypto_pwhash_str(
$password,
\Sodium\CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
\Sodium\CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);

Validating a password with Argon2i in PHP using libsodium

if (\Sodium\crypto_pwhash_str_verify($hash, $password)) {
// Login successful
}

If you're using Halite 2.0.0 or newer, the Password API uses Argon2i then encrypts the hashes using authenticated encryption. (This is preferable to "peppering".)

How to Safely Store a Password in the Long Term

I'm going to be proposing an RFC soon to add Argon2i as a possible algorithm to the password hashing API. If it gets accepted in time for PHP 7.1's feature freeze, we might expect to see Argon2i be the default as early as PHP 7.3 (which should release in 2018).

Thus, the long-term solution might simply be:

Hashing a password with Argon2i, in the future

$hash = password_hash($userPassword, PASSWORD_DEFAULT);

Validating a password with Argon2i, in the future

if (password_verify($userPassword, $hash)) {
// Login successful.
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
// Recalculate a new password_hash() and overwrite the one we stored previously
}
}

In Sum

There are things you can do to improve the security of your password hashes right now, but in the long run the password hashing API will come full circle and the lazy answer today will once again be the best practice answer tomorrow.

TL;DR: password_hash() and password_verify() will outlive bcrypt, so just use those unless you have a compelling reason to do more.

Local PHP Web App, how to protect the database password

There are a LOT of very robust external authentication providers out there. Firebase and OAuth to name a few. Technically speaking, no system is 100% hack-proof, but Firebase and OAuth provide would-be hackers a tough road to success



Related Topics



Leave a reply



Submit