I wrote this function in php to check user/pass against account on linux server. It works fine, but I am concerned a little about security.
/* Need to add www-data to group shadow (and restart apache)
$ sudo adduser www-data shadow
$ sudo /etc/init.d/apache2 restart
Needs whois to be installed to run mkpasswd
$ sudo apt-get install whois
Assumes that sha-512 is used in shadow file
*/
function authenticate($user, $pass){
// run shell command to output shadow file, and extract line for $user
// then split the shadow line by $ or : to get component parts
// store in $shad as array
$shad = preg_split("/[$:]/",`cat /etc/shadow | grep "^$user\:"`);
// use mkpasswd command to generate shadow line passing $pass and $shad[3] (salt)
// split the result into component parts and store in array $mkps
$mkps = preg_split("/[$:]/",trim(`mkpasswd -m sha-512 $pass $shad[3]`));
// compare the shadow file hashed password with generated hashed password and return
return ($shad[4] == $mkps[3]);
}
// usage...
if(authenticate('myUsername','myPassword')){
// logged in
} else {
// not valid user
}
Does adding www-data to the group shadow have a great security risk on a dedicated server on internal network? (I realise that on shared hosting server it could allow opportunity for hackers to use salt values to crack other user's passwords)
Are there any other security concerns with the method I am using?
Any suggestions to make it more reliable?
I'm not deeply familiar with how the shadow group works but giving PHP access to it sounds really dangerous - one PHP script with a broken include
call could get an attacker the contents of /etc/shadow
. While that's not tantamount to gaining root access, having the encrypted passwords in the open is still nasty, of course.
If there is no native Unix/Linux command that can authenticate a user that you could run selectively, I think your idea
The other way I tried - which also works is to make a shell script that uses su to log in as the user, and returns an exit code of 0 for success. This can then be called from within php file.
sounds much, much better, as it doesn't necessitate opening access to any higher-level resources. You may just have to set up some kind of rate limiting so an attacker can't disable local user accounts by doing thousands of failed login attempts on them.