Check hash validity - php

I'm trying to validate password against invalid hash stored in database. Instead of getting false (as I supposed) in this situation, my application dies with Invalid hash exception.
Is there any Yii2-built-in way to validate hash, before feeding it to validatePassword, to handle this kind of situation more gently?
Or the only way I'm left with is to copy code used by validatePassword:
if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches) || $matches[1] < 4 || $matches[1] > 30) {
throw new InvalidParamException('Hash is invalid.');
}
to my own code and simply not call validatePassword, when hash is invalid?

You can always use try - catch block in your password validation:
/**
* Validates password
*
* #param string $password password to validate
* #return boolean if password provided is valid for current user
*/
public function validatePassword($password)
{
try {
$data = Yii::$app->getSecurity()->validatePassword($password, $this->password_hash);
return $data;
} catch(\yii\base\InvalidParamException $e) {
return false;
}
}
Something like that, but why you even want to try to validate hash if it's already malformed? Maybe some criminal will pass something bad there, which can pass your login etc.

Related

Bcrypt check password in codeigniter

I have a problem when decrypting passwords hashed with bcrypt. I can't login when I use this code. So, are there any mistakes?
function login(){
if ($this->session->userdata('username'))
{
redirect('dasbor');
}
//fungsi login
$valid = $this->form_validation;
$username = $this->input->post("username");
$password = $this->input->post("password");
$hash = $this->db->get('users')->row('password');
$hashp = $this->bcrypt->check_password($password,$hash);
$valid->set_rules("username","Username","required");
$valid->set_rules("password","Password","required");
if ($hashp) {
if($valid->run()) {
$this->simple_login->login($username,$hashp, base_url("dasbor"), base_url("Auth/login"));
}
}
// End fungsi login
$data = array('title'=>'Halaman Login Admin');
$this->load->view('admin/login_view',$data);
}
please help me to solve this problem.
I know this is an old question, but I want to help others who face the same problem.
First thing first, you need to rework again on your algorithm. The password_verify() function needs 2 parameters:
Password, the text that the user input in the text field before submitting the form.
Hash, a hash that is already stored in your database.
The goal is to verify if Password and Hash are similar. As you know, the password_hash() will return a different result at different times even when you hash the same string. Because of that, you can not use this->db->where() active record.
So, what I would do are these simple 2 steps:
Create a function in the model (e.g. Main_model.php) for getting user data.
public function get_user($user) {
$this->db->where('username', $user);
return $this->db->get('user')->row_array();
}
Get the password from the controller and use password_verify
$get_user = $this->main_model->get_user($this->input->post('username'));
if(password_verify($this->input->post('password'), $get_user['password'])){
// Success
}
else {
// Not Success
}
And one additional tip from me, don't write any active record in the Controller. It is not neat for the MVC method.

Password value object that can be either hashed or raw

I've got the following value object (VO) Password. The password must be between 6 and 20 characters. But since my UserMapper is hashing the password before persisting the entity, I have no idea what validation logic I should have in this VO.
When UserMapper returns a User, the password is in a hashed form which is 60 characters long.
Does that mean I have to take into consideration both of these scenarios in my value object? Currently it would throw an InvalidArgumentException exception because the value would not be between 6 and 20 chars but 60 characters long (hashed).
namespace Models\Values\User;
use \InvalidArgumentException;
class Password
{
private $min = 6;
private $max = 20;
private $password;
public function __construct($password)
{
if (is_string($password) && !empty($password)) {
$length = $this->stringLength($password);
if ($length >= $this->min && $length <= $this->max) {
$this->password = $password;
}
} else {
throw new InvalidArgumentException(sprintf('%s must be a string from %s to %s characters.', __METHOD__, $this->min, $this->max));
}
}
public function __toString()
{
return $this->password;
}
private function stringLength($string)
{
$encoding = mb_detect_encoding($string);
$length = mb_strlen($string, $encoding);
return $length;
}
}
I agree with #kingkero in the comment above: Make that two different classes.
I suggest that HashedPassword is only creatable through a factory method on Password (possibly using a PasswordHashAlgorithm service given as an argument), which will be used to create a hashed password after Password has validated the input. Only HashedPasswords are persisted.
Client side password validation on the length could be on the textbox that contains the password string item.
After that, it should be considered a safe password (if the password store accepts it).
After that you should not set or get passwords from the password storage, but ask the store to verify the password for you.
So I think you are too late in checking the password strength, unless you can do it sooner.

Laravel 4 Auth::attempt returns false on correct values

I have login code that is supposed to work by attempting to authenticate the user using Laravel's Auth::attempt() method. This code works on another site of mine, I have altered it as instead of the Password in the database, it is stored as passwdEncrypted. I cannot change it as the database is in use by another application as well.
The code is below:
// check if in database
$isInDb = User::where('ReferenceCode', $username)->first();
if($isInDb) {
// is in database
// check if password is encrypted yet
if($isInDb->passwdEncrypted) {
// password is encrypted
if(Auth::attempt(array('ReferenceCode' => $username, 'passwdEncrypted' => $password))) {
// authenticated
$array = array();
$array['verified'] = 'true';
$array['type'] = Auth::user()->UserType;
return Response::json($array);
} else {
// not authenticated
$array = array();
$array['verified'] = 'false';
$array['type'] = $type;
return Response::json($array);
}
} else {
// password is not encrypted
// check if plain text password is correct
if($isInDb->Password == $password) {
// plain text password is correct
$hashed = Hash::make($password);
$arr = array('passwdEncrypted' => $hashed);
$updated = User::where('rsmsOnlineUserID', $isInDb->rsmsOnlineUserID)->update($arr);
if($updated) {
$newUser = User::find($isInDb->rsmsOnlineUserID);
echo $newUser->passwdEncrypted;
if(Auth::attempt(array('ReferenceCode' => $username, 'passwdEncrypted' => $password))) {
echo 'logged in';
} else {
dd(DB::getQueryLog());
echo 'could not log in';
}
} else {
echo 'did not update';
}
} else {
// plain text password is incorrect
$array = array();
$array['verified'] = 'false';
$array['type'] = $type;
return Response::json($array);
}
}
} else {
// not in database
return Respone::json(array('success' => 'false'));
}
What is happening: I can't log in, the username and password in the database is 1234, even if I hard code that, it does not work.
It first checks to see if the user is in the database, if it is, it checks to see if there is an encrypted password, if there is not, it will create one from the password given if it matches the plain text password in the database and then log the user in (I have no choice but to have the plain text password stored in the database, that is how they want it).
But it returns the {"verified":"false","type":"prospective_employee"} from the not authenticated part of the code. So neither of the Auth::attempt() blocks work.
I was logging them in manually but even Auth::login() won't work.
I have the following in my User model (with the main database table):
public function getAuthPassword()
{
return $this->Password;
}
/**
* Get the token value for the "remember me" session.
*
* #return string
*/
public function getRememberToken() {
return $this->remember_token;
}
public function setRememberToken($value) {
$this->remember_token = $value;
}
public function getRememberTokenName() {
return 'remember_token';
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return $this->email;
}
Please note that there is a field in the table called Password, but that is the plain text password, I need to authenticate against the passwdEncrypted field.
You cannot do this with Laravel, and for good reason, but it is ridiciously unsecure and dangerous.
I have no choice but to have the plain text password stored in the
database, that is how they want it
I dont understand - why are you storing BOTH an "unencrypted" and "encrypted" password? There is no point. You should only ever store encrypted passwords. There is no need for any other way, and you need to educate the people as to why.
This code works on another site of mine, I have altered it as instead
of the Password in the database, it is stored as passwdEncrypted. I
cannot change it as the database is in use by another application as
well.
The Laravel Auth code is hard coded to use the "password" column. You cannot simply change it to another colum. That is why your code is failing.
Since you are not using the password column, and since you are not using encrypted passwords, you might as well just create your own unsecure login system, customised to suit your requirements.

Converting from MD5 Legacy Auth System to CakePHP

I have a site which runs off an MD5 hashing scheme for passwords. As a way of supporting this legacy system, I've this answer to manually override the login system for now. But this isn't really ideal, as MD5 is pretty much universally known to be awful at encryption. So in the interest of security, what's the best way to migrate users over to the safer CakePHP auth system without causing them undue grief?
Figured it out thanks to this answer (albeit lightly modified). Basically, it updates the user behind the scenes to use the new system if the current system doesn't match up with it.
/**
* Login method
*/
public function login() {
$this->layout = 'homepage';
// If the user is already logged in, redirect to their user page
if($this->Auth->user() != null) {
$this->redirect();
} else {
// If this is being POSTed, check for login information
if($this->request->is('post')) {
if($this->Auth->login($this->loginHelper($this->request->data))) {
// Redirect to origin path, ideally
} else {
$this->Session->setFlash('Invalid username or password, try again');
}
}
}
}
/**
* Update password method
* #param array The user's data array
* #param Returns either a user object if the user is valid or null otherwise
*/
private function loginHelper($data) {
$username = $this->data['User']['username'];
$plainText = $this->data['User']['password'];
$user = current($this->User->findByUsername($username));
$salted = Security::hash($plainText, null, true);
if ($salted === $user['password']) {
return $user; // user exists, password is correct
}
$md5ed = Security::hash($plainText, 'md5', null);
if ($md5ed === $user['password']) {
$this->User->id = $user['id'];
$this->User->saveField('password', $plainText);
return $user; // user exists, password now updated to blowfish
}
return null; // user's password does not exist.
}

PHP Digest authentication with MD5

I wrote a class to authenticate a user using HTTP Authentication the Digest way. I read a few articles and I got it working. Now, I would like to let it make use of Md5 passwords, but I can't seem to get it working, this is the function authenticating the users.
public function authenticate() {
// In case the user is not logged in already.
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
// Return the headers.
$this->show_auth();
} else {
// Parse the given Digest-data.
$data = $this->parse_request($_SERVER['PHP_AUTH_DIGEST']);
// Check the data.
if (!$data) {
// Display an error message.
die($this->unauthorized);
} else {
// Based on the given information, generate the valid response.
$usr_password = "test";
// Generate the response partly.
$A1 = md5($data['username'].":".$this->get_realm().":".$usr_password);
$A2 = md5($_SERVER['REQUEST_METHOD'].":".$data['uri']);
// Generate the valid response.
$val_response = md5($A1.":".$data['nonce'].":".$data['nc'].":".$data['cnonce'].":".$data['qop'].":".$A2);
// Compare the valid response with the given response.
if ($data['response'] != $val_response) {
// Display the login again.
$this->show_auth();
} else {
// Return true.
return true;
}
}
}
}
So imagine the $usr_password="test" will be $usr_password=md5("test");
How do I compare passwords then?
Thanks.
The MD5 function is hashing function, one-directional method to produce the same result for the same input.
Thus, to compare $password1 to $password2 without revealing (comparing directly) both of them it should be enough to compare their hashes:
$hash1 = md5($password1); // hash for pass 1
$hash2 = md5($password2); // hash for pass 2
if ($hash1 === $hash2) {
// here goes the code to support case of passwords being identical
} else {
// here goes the code to support case of passwords not being identical
}
Is it clear enough? Let me know.

Categories