Storing passwords securely in MySQL, but still accessible by PAM - php

We have a PHP application that stores passwords just using the MD5 function (with no salt).
We have OpenSSH set to use pam-mysql to authenticate users from the same database.
We would like to switch to use hashed passwords and we are considering either: 1. doing it ourselves, (something like md5($salt."$".$password) or hash("sha256", $salt."$".$password)), or 2. using php's crypt function (which uses the OS crypt(3) if available).
The problem is that I have not found whether pam-mysql supports crypt(3) or any replacement pam module that does.
crpyt(3) uses a user supplied algorithm and salt: crypt('password', '$5$saltstring$') for sha256 which returns $5$saltstring$OH4IDuTlsuTYPdED1gsuiRMyTAwNlRWyA6Xr3I4/dQ5. Any language that uses the crypt(3) library will see that string and know to use sha256 with the given hash and expect the given result.
Is the first method sufficient or is there some PAM module out there that supports MySQL and crypt(3)?

Use sha512, either a mysql implementation or a php implementation. If you use md5 you're using a known insecure function which opens you up to liability.

you may also use 3DES encryption for stronger security.

Related

PHP - ldap_add userPassword crypt and password_hash

I am using PHP 7.1.
and create LDAP management page.
When using ldap_add() function.
there's ['userPassword'] field.
When I use below code, that works OK. (If salt does not exist, it's fine.)
$entry['userPassword'] = '{crypt}'.crypt('default_password');
Or below code is also works OK.
$entry['userPassword'] = '{MD5}'.'base64_encode(pack("H*", md5('default_password')));
But I read PHP recommend password_hash() function than crypt().
Can I use password_hash() function for LDAP? Is it possible?
UPDATE:
OK. then what what is the best solution for LDAP password ?
$salt = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.');
$entry['userPassword'] = '{crypt}'.crypt('defaultpassword', '$2y$10$'.$salt.'$');
This does not work.
PHPs Password-Hashing mechanism is intended for use when you want to handle passwords only within PHP. Then it's great to use password_hash to create and password_verify to verify the password. The used backend here is completely irrelevant.
LDAP on the other hand uses ldap_bind to not only verify a password, but to bind a user to an LDAP-Server. That's like logging into the Server. For that there are different Crypto-Algos that can be used like crypt or md5(which we do not use anymore…).
As this binding-mechanism can be used by different systems to verify a login, the by LDAP supported Crypto-Algos need to be used so that the LDAP-Server can handle the password-verification.
So when you want to use LDAP-Verification via bind on different systems with the password you are storing in LDAP you will not be able to use password_hash.
If you want to use the password only with your PHP-Application you can use password_hash but I would not put it into the userPassword-attribute as that is the one the LDAP-Server uses to verify a password given by bind. And you usually can only read that field when you are authenticated as either an Admin or the user in question, which you won't be able to login as due to the password not being able to be handled by the user. So you'd need to bind to the LDAP as admin-user which adds much more security issues to your application than the use of password_hash solves.
And I would also question what sense it makes to use LDAP as backend when you don't use the benefits of LDAP like one password for multiple systems. It's usually much easier to store informations in a database than to setup an LDAP just for a single project.
I depends on your directory I guess, but commonly passwords in LDAP are stored with a scheme {MD5}, {CRYPT}, etc.
If you want to use something else, you have to be compliant with the mechanisms that are supported by the directory you use.
For the advice about password_hash, the fact is that :
password_hash is only a wrapper of crypt with default options set
password_hash is not intended to create a hash for a dedicated authentication mechanism
It is recommended for developpers who need to store a hash in a database and compare future passwords against this hash without constraint about the hash mechanism used.
The fact that the LDAP protocol support these authentications, you have to comply with the mechanisms supported by the directory.
So as the password_hash function does not seem to provide the choice of the hash mechanism used, I would say that you can't use it. Or at least, it won't provide you more "security" to use it than crypt or other supported and readily available mechanisms in your directory.

Create and verify sha-512 password hashes with crypt() and PHP

The PHP function crypt() creates a hash for a password. It requires a second parameter for a random salt. This salt can also include additional instructions about which algorithm to use. Seems like a hack, but that's the API. So I add the $6$ prefix to get the SHA-512 hash I need. (Can't use bcrypt for the external non-PHP application that shall also be able to verify the hash. The hash must be verified from PHP and other applications with limited algorithms support.)
Now there are two problems that the PHP manual leaves me alone with:
1) Where do I get a random salt and what requirement does it need to satisfy? I've read about openssl_random_pseudo_bytes and I thought I'd just base64-encode it. But how many source bytes or encoded characters do I need?
2) How can I verify such a hash in PHP again? There doesn't seem to be a single function to do that. I believe I can call crypt again with the same salt as before, but to do that, I need to extract the hash and algorithm and whatever else is needed from the stored password hash. I've seen hashes with variable number of $ characters, so that doesn't seem like a good delimiter to split by.
I've read about phpass but it doesn't support sha-512, so I can't use that.
PHP version is 5.5.9 so some functions may not be available.

Local/Production Crypt Returning Different Hashes

PHP crypt function is returning different hashes on local and production server.
On localhost the crypt hash validation is working fine, but on production its not.
Local: PHP 5.4.4
Procution: PHP 5.3.10-1ubuntu3.5
Code:
echo crypt('123123123');
Local Example Response:
$1$7ymnm8q/$M6HLj2JEvzWGElqlwjAKm0
Production Example Response:
$6$sbttg2v6$2YAU3dNKR/.MRGmbBV4sR8vEhr/L8aOMTej1u3gArhgIiCiJ5IFJ
Citing from the PHP docu on crypt():
crypt() will return a hashed string using the standard Unix DES-based algorithm or alternative algorithms that may be available on the system.
So cyrpt() is not bound to a specific algorithm, but uses, what the system supports.
You may use the following constants to see, which are supported in the system you are running crypt():
CRYPT_STD_DES
CRYPT_EXT_DES
CRYPT_MD5
CRYPT_BLOWFISH
CRYPT_SHA256
CRYPT_SHA512
If you look at the examples in the docu, you'll see, that your local code uses MD5 for encryption, while the production server uses SHA-512.
Furthermore you don't specify a specific salt, so PHP will generate one for you, which will also differ in each invocation of crypt().
The systems use different default hashing algorithms: $1$ stands for MD5, $6$ for SHA-512
You should specify the algorithm explicitly using the salt parameter:
crypt('123123123', '$6$somerandomstring');
See crypt() documentation:
salt An optional salt string to base the hashing on. If not provided, the behaviour is defined by the algorithm implementation and
can lead to unexpected results.

How to make a permanent tripcode?

I mean, crypt()'s return is always different.
So how do websites like 4chan do to give a permanent tripcode to a password?
Are they stored in a database?
4chan's tripcodes are created using a specific formula, and are a shorter version of a hash. You can achieve the same effect by using MD5 or SHA1.
Encrypt string to MD5 (PHP):
$md5 = md5("$string");
Encrypt string to SHA1 (PHP):
$sha1 = sha1("$string");
There is no way to reverse the hashing process (just like tripcodes), but with time and power they can be "bruteforced" back to plain text.
It's quite common to salt a password, then hash it using DES, MD5, SHA, or newer hashes. The salt is then stored as part of the password.
PHP's crypt works this way, although the exact algorithm it uses to hash the password may be different between versions of PHP... and even between operating systems, although the latter supposedly changed in PHP 5.3. (PHP now includes its own hashing library instead of relying on the OS library, which is really, really important if you're using Windows, as crypt function on Windows only supported DES with 2-byte salt prior to this)
Edit:
Note: crypt has an optional second argument. Passing the encrypted password as the second argument will usually get PHP to detect the salt and algorithm used to originally hash the password, namely because everything other than DES start with $#$ where # is a number.
You pass the salt to crypt() as the second argument. This causes the output to use that salt instead of generating one on the fly.
The salt being randomly generated is why crypt("something") returns different results each time. If I run crypt("something", "ab"), it'll be identical every time. I don't have PHP here to check what the value is, though.
Wikipedia has an article about Tripcodes.
I think there's a table "tripcodes" where tripcodes were generated with the Wikipedia's and they are associated with strings they come from, no?
Yes password are stored in a database but without the use of crypt(). They use sha1() or encryption database function like AES_ENCRYPT() in mysql.

How do I create a unix password hash with php

I'm trying to create system users with a php script securely, In that, I'd like to be able to hash the password with the php script, so that their password shows up nowhere in the bash history.
How to I take a string, and hash it so it is a unix password hash?
$UX_PW = some_function('my_password');
exec("useradd -p $UX_PW newusername");
It's crypt() that implements the UNIX password hashing.
http://us.php.net/manual/en/function.crypt.php
Depending on your system, you're either looking for crypt() or md5().
Traditionally, unix uses DES-encrypted passwords (thats the 'crypt' function), with a 2-character salt (two random characters from the set [a-zA-Z0-9./]) which is prepended to the hash to perturb the algorithm.
Newer systems often use MD5 though.
Use crypt. Recent linux/unixes use CRYPT_MD5 or
CRYPT_BLOWFISH. MD5 is the most widely supported one. DES's are for old systems.
Also I should note that the MD5 version is not a simple MD5 sum operation, it also uses a "salt" value to make hashes not-precalculatable. [[ I made up this term :) ]]
The password-hashing used on UNIX, Linux, and other UNIX-like POSIX operating systems varies a lot. Most "passwd" hashing methods uses a modified DES algorithm (not true DES), they may apply the hashing to the input multiple times, and they use a salt of 16 or 24 bits. A specific answer of the method to produce a passwd-compatible hash depends on which operating system you're using.
The crypt() system call should be the way to do password hashing according to your operating system. You can access it in PHP using the function crypt().
As for which crypt algorithm to use, this depends on your operating system.
From the Ubuntu Intrepid man page on passwd (change password)
The security of a password depends upon the strength of the encryption algorithm and the size of the key space. The UNIX System encryption method is based on the
NBS DES algorithm and is very secure. The size of the key space depends upon the randomness of the password which is selected.
Also, instead of using crypt() you may prefer hash() because this allows you to keep the string setting for the hash algorithm elsewhere. If your code needs to use a different hash algorithm for other environments, you'll only have to change the string and not the name of the function.

Categories