I'm using slim for my framework and whenever I test it on Postman the the php cant read the parameters but when i convert it to md5 the php now can read the request. What could be my problem. The server is sending me null. Here is my code
DBOperations.php
//Method for user login
function userLogin($userName, $userPassword)
{
$password = md5($userPassword);
$stmt = $this->con->prepare("SELECT userID FROM users WHERE userName = ? AND userPassword = ?");
$stmt->bind_param("ss", $userName, $password);
$stmt->execute();
$stmt->store_result();
return $stmt->num_rows > 0;
}
index.php
//user login route
$app->post('/login', function (Request $request, Response $response) {
if (isTheseParametersAvailable(array('userName', 'userPassword'))) {
$requestData = $request->getParsedBody();
$userName = $requestData['userName'];
$userPassword = $requestData['userPassword'];
$password = md5($userPassword);
$db = new DbOperation();
$responseData = array();
if ($db->userLogin($userName, $userPassword)) {
$responseData['error'] = false;
$responseData['username'] = $db->getByUserName($userName);
} else {
$responseData['error'] = true;
$responseData['message'] = $password;
}
$response->getBody()->write(json_encode($responseData));
}
});
When the password is md5
{"error":true,"message":"d41d8cd98f00b204e9800998ecf8427e"}
When the password is not
{"error":true,"message":null}
You should do something like this
function userLogin($userName, $userPassword)
{
$stmt = $this->con->prepare("SELECT userID, password FROM users WHERE userName = ?");
$stmt->bind_param("s", $userName);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result( $userID , $password);
$result = $stmt->fetch();
if( password_verify($userPassword, $password)){
return true;
}
return false;
}
I don't use Mysqli, so I hope I got that part right.
The important thing is that you should not use the password as part of the WHERE clause. There are several reasons for this
your relying on getting a result instead of checking the result against input data. If there is a problem with your query it could allow logins when it shouldn't
your not checking the password using a secure method designed for doing it.
Etc.
You should use
password_hash
And
password_verify
Related
I have a recurring problem in my Android application.
Basically I am using PHP and a MYSQL database to register and login users into my app.
Registration works fine. I am able to connect to the database and insert the new user into the table without any problems.
The issue I am facing is when logging into the app. Whenever I call the login url, I am getting the following error:
BasicNetwork.performRequest: Unexpected response code 500 for URL.
I tried using other tools to access this url and posting the parameters manually to eliminate the issue that the error might be coming from my app code. In fact I got a Generic 500 Internal Server Error. Tested the register URL with this tool too and it worked perfectly.
My PHP classes all call the same script to get the connection details, so there is no problem with that either since registration works.
Here is my code below:
Login class:
<?php
require_once 'UserFunctions.php';
$db = new UserFunctions();
$response = array("error" => FALSE);
if (isset($_POST['email']) && isset($_POST['password'])) {
$email = $_POST['email'];
$password = $_POST['password'];
$user = $db->getUserByEmailAndPassword($email, $password);
$count = $db->getUserCount();
if ($user != false) {
$response["error"] = FALSE;
$response["uid"] = $user["unique_id"];
$response["user"]["name"] = $user["name"];
$response["user"]["email"] = $user["email"];
echo json_encode($response);
} else {
$response["error"] = TRUE;
$response["error_msg"] = "Login credentials are wrong. Please try again!";
echo json_encode($response);
}
} else {
$response["error"] = TRUE;
$response["error_msg"] = "One of the required parameters is missing!";
echo json_encode($response);
}
?>
UserFunctions class:
<?php
class UserFunctions {
private $conn;
function __construct() {
require_once 'include/DbConnect.php';
$db = new DbConnect();
$this->conn = $db->connect();
}
function __destruct() {
}
public function storeUser($name, $email, $password) {
$uuid = uniqid('', true);
$hash = $this->hashSSHA($password);
$password = $hash["encrypted"];
$salt = $hash["salt"];
$stmt = $this->conn->prepare("INSERT INTO users(unique_id, UserName, UserEmail, UserPassword, salt) VALUES(?, ?, ?, ?, ?)");
$stmt->bind_param("sssss", $uuid, $name, $email, $password, $salt);
$result = $stmt->execute();
$stmt->close();
if ($result) {
$stmt = $this->conn->prepare("SELECT * FROM users WHERE UserEmail = ?");
$stmt->bind_param("s", $email);
$stmt->execute();
$user = $stmt->get_result()->fetch_assoc();
$stmt->close();
return $user;
} else {
return false;
}
}
public function getUserByEmailAndPassword($email, $password) {
$stmt = $this->conn->prepare("SELECT * FROM users WHERE UserEmail = ?");
$stmt->bind_param("s", $email);
if ($stmt->execute()) {
$user = $stmt->get_result()->fetch_assoc();
$stmt->close();
return $user;
} else {
return NULL;
}
}
public function isUserExisted($email) {
$stmt = $this->conn->prepare("SELECT UserEmail FROM users WHERE UserEmail = ?");
$stmt->bind_param("s", $email);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows > 0) {
$stmt->close();
return true;
} else {
$stmt->close();
return false;
}
}
public function hashSSHA($password) {
$salt = sha1(rand());
$salt = substr($salt, 0, 10);
$encrypted = base64_encode(sha1($password . $salt, true) . $salt);
$hash = array("salt" => $salt, "encrypted" => $encrypted);
return $hash;
}
public function checkhashSSHA($salt, $password) {
$hash = base64_encode(sha1($password . $salt, true) . $salt);
return $hash;
}
}
?>
I found where my problem was.
For all those who encounter the very nasty error 500, check your logs. Occured to me that once I checked the logs, I found that the method checkhashSSHA() was never being used, and this was causing the following error:
PHP Fatal error: Call to undefined function checkHashSSA() in /xxx/xxx/xxx/xxx/UserFunctions.php on line 54
Hence I added the following code to decrypt the password:
public function getUserByEmailAndPassword($email, $password) {
$stmt = $this->conn->prepare("SELECT * FROM users WHERE UserEmail = ?");
$stmt->bind_param("s", $email);
if ($stmt->execute()) {
$user = $stmt->get_result()->fetch_assoc();
$salt = $user['salt'];
$userPassword = $user['UserPassword'];
$hash = $this->checkhashSSHA($salt, $password);
if ($userPassword == $hash) {
return $user;
}
$stmt->close();
} else {
return NULL;
}
}
This solved my error.
Just for the record, logs for such errors are usually found in the following location: var/log/apache2/error.log You may need to make some change to the php.ini file to log these errors.
Hope this helps anyone with the 500 error ;)
I have a problem with PHP function password_verify. I've written simple PHP function that uses _GET, takes 3 parameters: $user_unique_id, old_password and new_password. It verifies if old password and the password stored in database are the same. I use hash from my database and compare it with old password using password_verify() fucntion but it returns false even whem I'm 100% sure the passwords are the same. Can somebodyb help me with this problem? I've checked MySQL queries and all works very well. I return updated_at time which later I encode to JSON.
This is my function in main script changeuserpassword.php I call from link:
<?php
require_once 'include/DB_Functions.php';
$db = new DB_Functions();
// JSON Response Array
$response = array();
// Receiving The Post Params
$old_password = $_GET['old_password'];
$new_password = $_GET['new_password'];
$user_unique_id = $_GET['user_unique_id'];
// Change User Password
$user = $db->changeUserPassword($user_unique_id, $old_password, $new_password);
if ($user != false) {
$response["error"] = false;
$response["user"]["updated_at"] = $user["updated_at"];
echo json_encode($response);
} else {
$response["error"] = true;
$response["error_msg"] = "Podano nieprawidłowe stare hasło";
echo json_encode($response);
}
?>
This is the function I use in changeuserpassword.php main script. It is called changeUserPassword:
/**
* Change User Account Password
*/
public function changeUserPassword($user_unique_id, $old_password, $new_password) {
$stmt = $this->conn->prepare("SELECT user.`encrypted_password`
FROM `user`
WHERE user.`unique_id` = ?"); // Preparing SELECT Query To The `user` Table
$stmt->bind_param("s", $user_unique_id); // Binding With Params
if ($stmt->execute()) {
$user = $stmt->get_result()->fetch_assoc(); // Fetching Rows From Query
$stmt->close();
$password_hash = $user["encrypted_password"]; // Decrypting Hashed Password
// Checking Currrent Password Identity With Decrypted Password
if (password_verify($old_password, $password_hash)) { // Old Password And Current One Are The Same
$encrypted_password = password_hash($new_password, PASSWORD_DEFAULT); // Hashing New Password
$stmt = $this->conn->prepare("UPDATE user
SET user.`encrypted_password` = ?, user.`updated_at` = NOW()
WHERE user.`unique_id` = ?");
$stmt->bind_param("ss", $encrypted_password, $user_unique_id);
$result = $stmt->execute();
$stmt-close();
// Checking For Succesfull UPDATE
if ($result) {
$stmt = $this->conn->prepare("SELECT user.`updated_at`
FROM `user`
WHERE user.`unique_id` = ?");
$stmt->bind_param("s", $user_unique_id);
$stmt->execute();
$user = $stmt->get_result()->fetch_assoc(); // Fetching Rows From Query
$stmt->close();
return $user;
}
} else { // Old Password And Current One Are Different
return false;
}
}
}
Edit
Here is my database screenshot:
My script runs but it always return false which means password_verify() returns false.
Solved
The problem was $stmt->close() statement. I used them too often and thats why the script didn't work.
After debugging with #anton86993 in a chat, we found the bug to be the use of too many $sql->close() statements, when they weren't needed.
There is no reason to have that many close statements, as PHP automatically closes the connection to SQL when the script is done. A reason to have a close statement could be to release a connection to SQL, if you have a limited amount of connection at once or the obvious one to release resources.
So I'm enabling users to create accounts with a username and password. I have managed to encrypt the password when a user creates a new account using:
$hash = password_hash($password, PASSWORD_BCRYPT);
However I'm having trouble with password_verify when logging in, could someone please help me with what I have? I know it's something like this:
password_verify($password, $hash)
But I don't know how to structure it or where to add it in the code. Thanks in advance. This is what I have:
<?php
if (isset($_GET["username"]) && isset($_GET["password"]) ){
$username = $_GET["username"];
$password = $_GET["password"];
$result = login( $username, $password);
echo $result;
}
function makeSqlConnection()
{
$DB_HostName = "";
$DB_Name = "";
$DB_User = "";
$DB_Pass = "";
$con = mysql_connect($DB_HostName,$DB_User,$DB_Pass) or die(mysql_error());
mysql_select_db($DB_Name,$con) or die(mysql_error());
return $con;
}
function disconnectSqlConnection($con)
{
mysql_close($con);
}
function login($username, $password)
{
$con = makeSqlConnection();
$sql = "select * from login where username = '$username' and password = '$password';";
$res = mysql_query($sql,$con) or die(mysql_error());
$res1 = mysql_num_rows($res);
disconnectSqlConnection($con);
if ($res1 != 0) {
return 1;
}else{
return 0;
}// end else
}// end of Function
?>
The general practice is as follows:
Fetch password hash from the database where the username = the inputted username.
If rows are found, then there's a user
Now you compare the inputted password against the hash stored in the database.
I'll outline the above flow in some pseudo code for you here:
$query = SELECT password FROM users WHERE username = '$username'
$data = FETCH_THE_DATA($query);
if(password_verify($USER_INPUTTED_PASSWORD, $data['password'])) {
// password is correct
} else {
// password is in-correct
}
Notes
Stop using mysql_* functions. The library is deprecated as it's unreliable and will be removed in future releases of PHP.
You're better off using PDO or MySQLi Prepared Statements
You should always read the manual - password_verify(), it states clearly that you compare the "user inputted password" against the hashed version which is stored in your database.
Since I'm feeling good and sleepy today, I'll write a bunch of codes.
This is an example how to use PDO with prepared statement. You will have to tweak it according to your needs and you have to check if the post/get not empty as well.
I prefer to use POST request for login so this example will use POST request..
This is my user class. Which use placeholders and binding instead of passing the parameters into the query directly. This will give some protections against SQL injection attack.
class User{
private $dbh;
function __construct(){
$this->dbh = new PDO("mysql:host=".DB_SERVER.";dbname=".DB_NAME.';charset=utf8mb4', DB_USER, DB_PASSWORD) or die('db connect error');
}
function create($username, $password){
$status = false;
try{
$stmt = "INSERT INTO login (username, password)
VALUES (?, ?)";
$qry = $this->dbh->prepare($stmt);
$qry->bindParam(1, $username);
$qry->bindParam(2, $password);
$status = $qry->execute();
}catch(PDOException $e){
$e->getMessage();
}
$qry->closeCursor();
return $status;
}
public function getPassword($username){
$status = false;
try{
$stmt = "SELECT * FROM login WHERE username = ? LIMIT 1";
$qry = $this->dbh->prepare($stmt);
$qry->bindParam(1, $username);
$qry->execute();
$status = $qry->fetch(PDO::FETCH_ASSOC);
}catch(PDOException $e){
$e->getMessage();
}
$qry->closeCursor();
return $status;
}
}
This is how to create the user. Note that I don't check if the username already exist. You can either implement it yourself or use unique index on username column provided that the collation is case insensitive.
I have also increased the cost from the default that is 10 and I defined PASSWORD_DEFAULT to be used because I want the PHP engine to always use the strongest available algorithm (currently bcrypt).
function hashPassword($password){
$password = password_hash($password, PASSWORD_DEFAULT,array('cost' => 16));
return $password;
}
$user = new User;
$_POST['password'] = hashPassword($_POST['password']);
if(!$user->create(trim($_POST['username']),$_POST['password'])){
echo 'Failed creating user';
}else{
echo 'User created';
}
This is how to verify the password.
$user = new User;
$getPassword = $user->getPassword(trim($_POST['username']));
if(!$getPassword){
echo 'Error fetching user';
}else{
if(!password_verify($_POST['password'], $getPassword['password'])){
echo 'Login failed';
}else{
echo 'Login successful';
}
}
I am trying to write a parametrised login function in PHP.
The function should get the $id and $pass bind and execute statement and return an associative array from the database with $id, $password, $user_first_name.
Checking for user id and password validation, if true the session should start and set the session with the username from the database.
For some reason I can't get this working. Any suggestions?
Thanks!
public function logIn($id, $password)
{
$stmt = $this->link->prepare("SELECT user_id, user_name, user_password FROM Users WHERE user_id = ? ");
$stms->bind_param('i', $user_id);
if ($stmt->execute())
{
$result = $stmt->get_result();
while($row = $result->fetch_array(MYSQLI_ASSOC))
{
$dbuser_id = $row['user_id'];
$dbpassword = $row['user_password'];
$dbuser_first_name = $row['user_first_name'];
}
if($id == $dbuser_id and $password == $dbpassword)
{
session_start();
$_SESSION['session_user_first_name'] = $dbuser_first_name;
}
else
{
session_unset();
echo "Credentials do not match";
}
}
}
You have
$stms->bind_param('i', $user_id);
But your function signature is:
public function logIn($id, $password)
So you probably want:
$stms->bind_param('i', $id);
Have a look at $stms->bind_param('i', $user_id);:
stms should be stmt
$user_id should be $id
...
I have a PHP page that registers and logs in users. When I enable sha1, the user gets created and the encrypted password is stored in the DB, but they cannot log in. When I comment out the line to encrypt in both the user creation section as well as the login section, everthing works. Here is my code to create the user:
function add_member($nick_name, $email_address, $password) {
global $db;
$password = sha1($password);
$query = "INSERT INTO members
(nick_name, email_address, password)
VALUES
('$nick_name', :email_address, :password)";
$statement = $db->prepare($query);
$statement->bindValue(':email_address', $email_address);
$statement->bindValue(':password', $password);
$statement->execute();
$statement->closeCursor();
}
Here is my code to validate the user:
function is_valid_member($email_address, $password) {
global $db;
$password = sha1($password);
$query = "SELECT member_ID
FROM members
WHERE email_address = :email_address AND password = :password";
$statement = $db->prepare($query);
$statement->bindValue(':email_address', $email_address);
$statement->bindValue(':password', $password);
$statement->execute();
$valid = ($statement->rowCount() == 1);
$statement->closeCursor();
return $valid;
}
Again, when I comment out the "$password = sha1($password);" in both sections, everything works but the password is clear text.
Thanks!
try to debug like this, echo your $password = sha1($password); and check your database entry, might be your datatype length truncated some text in stored password