When a user creates a account on my website then their password is stored using SHA512. My problem is when the user tries to login with their password, i believe i am verifying the password incorrectly however i cannot see what i have done wrong.
Here is my register script which works :
$uname = mysql_real_escape_string($_POST['uname']);
$sname = mysql_real_escape_string($_POST['sname']);
$email = mysql_real_escape_string($_POST['email']);
$upass = mysql_real_escape_string($_POST['pass']);
$upass = hash('SHA512', $upass);
The password 'Test' is stored in the database as:
ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f88
Here is my login script:
if($row['password']==hash('SHA512', $upass))
{
$_SESSION['user'] = $row['user_id'];
header("Location: account.php");
If any body could please edit my login code so that it can retrieve and verify the SHA512 string then it would be greatly appreciated.
I am not worried about totally changing my login system to make it more secure, it is a very simple system which is only used to store a users preferences for the site, please could we just sick to using SHA512.
Here is the hash_equals() for php version >= 5.6.0 If you are using lower version then you can use code from below.
if(!function_exists('hash_equals')) {
function hash_equals($str1, $str2) {
if(strlen($str1) != strlen($str2)) {
return false;
} else {
$res = $str1 ^ $str2;
$ret = 0;
for($i = strlen($res) - 1; $i >= 0; $i--) $ret |= ord($res[$i]);
return !$ret;
}
}
}
Matching hash.
$expected = crypt('Test', '$2a$07$addsomecustomstring$');
$correct = crypt('Test', '$2a$07$addsomecustomstring$');
$wrong = crypt('tets', '$2a$07$addsomecustomstring$');
var_dump(hash_equals($expected, $correct)); //true
var_dump(hash_equals($expected, $wrong)); //false
Since you already calculated hash above you no longer need to call hash function again in comparison:
if($row['password']==$upass)
instead of:
if($row['password']==hash('SHA512', $upass))
Related
In short, I want to login on my site and I want to login in encrypted form in php codes. I want to use Base64 and SHA256, SHA 256 for encryption.
I would like to know if it is possible to convert this ciphertext into PHP language, I need to convert the generated passwords to be accepted on my site's login system, but I do not know how to do this.
In Python I have a database with passwords generated with this encryption:
base64.b64encode(hashlib.sha256(hashlib.sha256(password).hexdigest() + "\xf7\x1a\xa6\xde\x8f\x17v\xa8\x03\x9d2\xb8\xa1V\xb2\xa9>\xddC\x9d\xc5\xdd\xceV\xd3\xb7\xa4\x05J\r\x08\xb0").digest())
PHP:
<?php
if($_POST){
$name = trim($_POST["name"]);
$sifre = trim($_POST["sifre"]);
if(!$name || !$sifre){
echo '<div class="hata">kullancı adı ve sifre bos bırakılamaz</div>';
}else {
$uye = $db->prepare("select * from users where Username=? and Password=? and uye_onay=?");
$uye->execute(array($name,$sifre,1));
$z = $uye->fetch(PDO::FETCH_ASSOC);
$x = $uye->rowCount();
if($x){
$_SESSION["uye"] = $z["Username"];
$_SESSION["eposta"] = $z["uye_eposta"];
$_SESSION["rutbe"] = $z["uye_rutbe"];
$_SESSION["id"] = $z["PlayerID"];
header("location:index.php");
}elseif($z["uye_onay"] == 0){
echo '<div class="hata">uyeliğiniz onaylanmadı yonetici onayını bekleyin..</div>';
} else {
echo '<div class="hata">uye adı yada sifreniz yanlıs</div>';
}
}
?>
Your Python code:
base64.b64encode(hashlib.sha256(hashlib.sha256(password).hexdigest() + "\xf7\x1a\xa6\xde\x8f\x17v\xa8\x03\x9d2\xb8\xa1V\xb2\xa9>\xddC\x9d\xc5\xdd\xceV\xd3\xb7\xa4\x05J\r\x08\xb0").digest())
PHP equivalent:
base64_encode(
hash('sha256',
hash('sha256', $password) . "\xf7\x1a\xa6\xde\x8f\x17v\xa8\x03\x9d2\xb8\xa1V\xb2\xa9>\xddC\x9d\xc5\xdd\xceV\xd3\xb7\xa4\x05J\r\x08\xb0",
TRUE
)
);
I have added the password_hash PHP function to my registration page, where users create accounts and store passwords. I applied the same password_hash line of code in the registration form. The data is saved in the database, but when I try to log in, the password submitted isn't matching the password stored. I also tried the password_verify function, which I read in the PHP manual, but nothing works. I really don't know what else to do, after trying and trying, so if anybody has an advice, I'd appreciated it.
P.S. I'm currently using PHP version 5.6.25.
Here's the code:
<?php
// AJAX CALLS THIS LOGIN CODE TO EXECUTE
if(isset($_POST["e"])){
// CONNECT TO THE DATABASE
include_once("PHP_Includes/db.php");
// GATHER THE POSTED DATA INTO LOCAL VARIABLES AND SANITIZE
$e = mysqli_real_escape_string($db, $_POST['e']);
$p = password_hash($_POST['p'], PASSWORD_DEFAULT,['cost' => 15]);
// FORM DATA ERROR HANDLING
if($e == "" || $p == ""){
echo "login_failed";
exit();
} else {
// END FORM DATA ERROR HANDLING
$sql = "SELECT id, username, password FROM users WHERE email='$e' AND activated='1' LIMIT 1";
$query = mysqli_query($db, $sql);
$row = mysqli_fetch_row($query);
$db_id = $row[0];
$db_username = $row[1];
$db_pass_str = $row[2];
if($p != $db_pass_str){
echo "login_failed";
exit();
} else {
// CREATE THEIR SESSIONS
$_SESSION['userid'] = $db_id;
$_SESSION['username'] = $db_username;
$_SESSION['password'] = $db_pass_str;
}
}
exit();
}
?>
login() function:
function login(){
var e = _("email").value;
var p = _("password").value;
if(e == "" || p == ""){
_("status").innerHTML = "Fill out all of the form data";
} else {
_("loginbtn").style.display = "none";
_("status").innerHTML = 'please wait ...';
var ajax = ajaxObj("POST", "index.php");
ajax.onreadystatechange = function() {
if(ajaxReturn(ajax) == true) {
if(ajax.responseText == "login_failed"){
_("status").innerHTML = "Login unsuccessful, please try again.";
_("loginbtn").style.display = "block";
} else {
window.location = "user.php?u="+ajax.responseText;
}
}
}
ajax.send("e="+e+"&p="+p);
}
}
Your understanding of how password_hash() works is a bit off. Unlike using sha1() or md5() (both of which you should avoid for storing passwords!), the password_hash() doesn't return the same string for every time it's called, even for the same string.
For example:
var_dump(password_hash("hello_world", PASSWORD_DEFAULT));
var_dump(password_hash("hello_world", PASSWORD_DEFAULT));
would output (for example, the strings returned by password_hash() varies for each time its called)
string(60) "$2y$10$Da2HG0dcvfI.3qBivR8Mpu9U5S06PBZ3415lDEh3EcDZ/fELZzHgC"
string(60) "$2y$10$zL6745UkPEvZWS5w1Keco.IKi7ssl.PqldGxucDYHaJW3vgCc366a"
Notice that they are different, even when the function is called twice on the same value? This means, that you cannot compare the stored password against $p = password_hash($_POST['p'], PASSWORD_DEFAULT,['cost' => 15]); like you are currently doing, because the password_hash() function returns a different string every time - you need to use the function password_verify() to verify the password, like below
$p = $_POST['p'];
if (password_verify($p, $fromDataBase)) {
// Valid password!
}
So instead of...
$p = password_hash($_POST['p'], PASSWORD_DEFAULT,['cost' => 15]);
you want
$p = $_POST['p'];
and instead of...
if($p != $db_pass_str){
you want
if (!password_verify($p, $db_pass_str)) {
And two notes on security:
You are not using prepared statements, which you REALLY should! See a link for mysqli_prepare() below. You should treat all your user-input as dangerous, and therefor use prepared statements for all SQL queries that accepts user-input. (When using prepared statements, you don't want to use mysqli_real_escape_string() - use one or the other, most preferably prepared statements!)
You are storing a password in a session - this is highly discouraged, as sessions can be "hijacked".
Readingmaterial:
http://php.net/manual/en/function.password-verify.php
http://php.net/manual/en/mysqli.prepare.php
How can I prevent SQL injection in PHP?
I'm writing log in code for the only user in my db.
But the password_verify function doesn't seem to work. When I echo both the hash from the db and the password written in the form, I see them, so there's no problem with the query or the $_POST.
Here's my code:
the log in:
$passwordFromForm = htmlspecialchars($_POST['password']);
$nmbr = 12; // it's the user's id.
$sql = "SELECT * FROM user WHERE iduser = $nmbr";
$res = mysqli_query($conn, $sql);
// $row = mysqli_fetch_assoc($res);
while($row = $res->fetch_assoc()) {
$hashFromDB = $row['hash'];
}
if(password_verify($passwordFromForm, $hashFromDB)) {
echo "success";
header("Location: ../admin.php");
}
else {
echo "The hash is:" . $hashFromDB . "and the pass is:" . $passwordFromForm;
//this echoes the correct hash and string
}
Thanks in advance.
The function password_verify() is dependent with password_hash(), you can check the algorithm password_hash() used whether the same with password_verify(), check the res with password_get_info($hash)
You should not do any escaping of the password, before feeding it to the password_hash() / password_verify() function. So remove the call to htmlspecialchars() and make sure that your database field holding the hash, is of type varchar(255).
I want to reset user password using php. i got user's current and new password from html form . here's php script to reset password. But it always executes else part even if user enters correct password. how?any solution? i know there might be a simple error but i'm new at this and couldnt find any error.
$uid = $_SESSION['uid'];
$current_pass = $_POST['org_pass'];
$new_pass = $_POST['new_pass'];
if(isset($_POST['submit']))
{
$act_pass = $db_con->prepare("SELECT password FROM user WHERE u_id= ?");
$act_pass->bindParam(1,$uid);
$act_pass->execute();
$actual_pass = $act_pass->fetchColumn();
define('SALT', 'flyingrabbit');
$typed_pass = md5(SALT.$actual_pass);
if ($typed_pass == $current_pass)
{
$new_pass1 = md5(SALT . $new_pass);
$res = $db_con->prepare("UPDATE user SET password= ? WHERE u_id=?");
$res->bindParam(1,$new_pass1);
$res->bindParam(2,$uid);
$res->execute();
header("Location: profile.php");
exit;
}
else
{
echo "<script type=\"text/javascript\">window.alert(\"You entered wrong password.\");window.location.href = 'profile.php';</script>";
}
}
This looks wrong:
$actual_pass = $act_pass->fetchColumn();
// ...
$typed_pass = md5(SALT.$actual_pass);
if ($typed_pass == $current_pass)
You are hashing the information you got from the database which - I assume - is already hashed.
You probably want:
$actual_pass = $act_pass->fetchColumn();
// ...
$typed_pass = md5(SALT.$current_pass);
if ($typed_pass == $actual_pass)
Note that md5 is not recommended to hash passwords.
You should compare hashed $current_pass and **$actual_pas**s.
Replace
$typed_pass = md5(SALT.$actual_pass); with $typed_pass = md5(SALT.$current_pass);
$typed_pass == $current_pass with $typed_pass == $actual_pass
It goes to the else statement because you compare $typed_pass == $current_pass but on the previous line you do this $typed_pass = md5(SALT.$actual_pass) you compare a hashed, salted password to a plain text password
I used this hash function for a while (got it from the internet). The thing is it used to work immediately but now it is complaining about a paramter. The following is the code:
function generateHash($plainText, $salt = null)
{
if ($salt === null)
{
$salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
}
else
{
$salt = substr($salt, 0, SALT_LENGTH);
}
return $salt . sha1($salt . $plainText);
}
So I would use this code in the method call:
validateUserInput($userid, $pass);
and validateUserInput is:
function validateUserInput($username, $password)
{
//$username = mysql_real_escape_string($username);
//$password = mysql_real_escape_string($password);
if(!$username || !$password)
{
//$errors['credentials'] = 'Missing Credentials!';
//$_SESSION['errors_array'] = $errors;
//echo $errors['credentials'];
header("LOCATION:XXXXXXX.php");
}
$local_salt = generateHash($password);
//echo $local_salt;
$groupid;
if($username != null && $password !=null)
{
connectToServer();
$result = mysql_query("SELECT * FROM users WHERE hashkey = '{$local_salt}'");
while($row_access = mysql_fetch_array($result))
{
$groupid = $row_access['groupid'];
}
if(!isset($result))
{
$errors['not_found_user'] = 'No Users Found with Provided Credentials!';
//$_SESSION['errors_array'] = $errors;
$userfound = 0;
$_SESSION['user_available'] = $userfound;
}elseif(isset($result)){
$_SESSION['user_logged'] = array('username' => $username, 'password' => $password, 'salt' => $local_salt, 'groupid' => $groupid);
$userfound = 1;
//echo "stored";
$_SESSION['user_available'] = $userfound;
}
}
}
finally the error is:
Warning: substr() expects parameter 3 to be long, string given in /home/XXXX.php on line 64
This is pointing to the function generateHash()
The error itself tells you everything. The constant SALT_LENGTH is not a long. I suspect it's not defined at all, so PHP converts the bare string to a string ("SALT_LENGTH") and passes that to substr(), which complains.
That being said... This code is dangerously wrong:
if(!isset($result)): Really? This condition will always be false because $result will always be set (unless you run into a problem with mysql_query(), but that doesn't tell you anything about the valididty of the login). And since mysql_query() never returns null, no logins will ever be rejected.
This query:
SELECT * FROM users WHERE hashkey = '{$local_salt}'
Is invalid. $local_salt = generateHash($password);. From the generateHash function, if a salt is not given, one will be randomly created for you. Thus, every call to generateHash will generate a new hash, which means it can't be compared to anything in the database.
On the basis of the two (very) egregious mistakes above, I would throw away this piece of code for good.
The correct way to check for a valid hash when a salt is used is something like:
$_SESSION['user_logged'] = null;
// fetch hashed pw from db, where username is the submitted username
$result = mysqli_query("SELECT hash FROM users WHERE username = '{$username}'");
if ($result->num_rows != 0)
{
$row = $result->fetch_assoc();
$hash = $row['hash'];
$salt = substr($hash, 0, SALT_LENGTH); // extract salt
if (generateHash($password, $salt) == $hash)
{
// login successful.
$_SESSION['user_logged'] = $username; // don't store passwords here
}
}
// if $_SESSION['user_logged'] is not set, the login failed
if (!isset($_SESSION['user_logged']))
{
// you *don't* want to tell people which one (login or pw) is invalid
echo 'Invalid login or password';
}
Note: It's very important that the SALT_LENGTH is at most 32, or this won't work because of the way generateHash() is implemented.
Clearly SALT_LENGTH is not an integer. Find where it's defined and correct this.
Instead of making a new hashing function each time you write an application , you should utilize the one provided to you by php: crypt() ( i would recommend to go with any blowfish or sha256+ hash ).
And when selecting information from database, you should select it by username and then, with php, check if hash fits the password.