PHP Activating account with UPDATE SQL - php

OK I have this code to send an email account verification link
$verifyemail = $clean['email'];
$to = $verifyemail;
$subject = 'Virtual Pierz Close | Verify Your Account';
$message = "Thanks for registering with VPC, on clicking the verification link below, your account will be confirmed, you can then go ahead buy Virtual Properties, donating £5 each time to the worthwhile charity.
http://www.cambrianvacation.co.uk/vpc/registered.php?
email='$verifyemail'&hash='$hash1' ";
$headers = 'From:noreply#cambrianvacation.co.uk'; // Set from headers
mail($to, $subject, $message, $headers);
And then I have this code, that is trying to activate the account by setting active = 1 in the database, which will then be part of the access control logic at login, without active = 1, there is no login, amongst other protection
if(isset($_GET['email']) && !empty($_GET['email']) AND isset($_GET['hash']) && !empty($_GET['hash'])){
// Verify data
$accountemail = $_GET['email'];
$accounthash = $_GET['hash'];
}
$accountActive = 1;
$notactive = 0;
$username = '';
$password2 = '';
$username = 'xxxxxxx';
$password2 = 'xxxxxxx';
$db1 = new PDO('mysql:host=localhost;dbname=xxxxxxxxxxxxx', $username, $password2, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$db1->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db1->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try{
$search = $db1->prepare("SELECT email, hash, active FROM users WHERE email = :email AND hash= :hash AND active = :active");
$search->bindParam(':email', $accountemail);
$search->bindParam(':hash', $accounthash);
$search->bindParam(':active', $notactive);
$search->execute();
$colcount = $search->columnCount();
}catch(PDOException $e) {
$e->getMessage();
}
print_r($colcount);
if($colcount === 3){
//try{
$update = $db1->prepare("UPDATE users SET active=:active WHERE email=:email AND hash=:hash AND active = :active");
$update->bindParam(':active', $accountActive);
$update->bindParam(':email', $accountemail);
$update->bindParam(':hash', $accounthash);
$update->bindParam(':active', $notactive);
$update->execute();
//}catch(PDOException $e) {
// $e->getMessage();
//}
However I cannot get the active column to update.
I've also thought about using the GET['email'] could be subject to semantic url attacks, however the logic won't activate the account without the matching hash, which is randomly generated with crypt().........
If anyone can see any security holes in the code, please tell me.........

There really is no reason to make two separate queries here. Why not just have one query to update the record based on hash and email and active = 0? If the count of modified rows = 1, then you had a success, else you had a failure. You probably don't care why it failed, as it would be bad from a security perspective to indicate back to the user why update failed (i.e. bad email, bad hash, already active user, etc.).
That being said, your problem actually lies in the fact that your update uses ? style bindings, while you are using bindParam() with :param style bindings. This won't work since those values are not present in the prepared statement.
So just use this one single query:
UPDATE users SET active = 1 WHERE email = :email AND hash = :hash AND active = 0
Obviously if you think you are going to change the value for active/non-active then feel free to use a parameter for those as well, but my guess is you would want to treat that as a boolean-style tinyint field with only allowable values of 0 and 1, so there is really no point in having the parametrization there.

What you could do, is not include "email" at all.
You could try to gen the url by doing this:
$secret = "1032940fdjsjdkf##$!##%djsfisd";
$hash = md5($email.$secret);
$url = "http://www.cambrianvacation.co.uk/vpc/registered.php?hash=".$hash;

In the update query, you are using "?" for parameters, but then you try to set them as named with bindParam(). You should use
$update->execute(array($accountActive, $accountemail, $accounthash, $notactive));
Or modify the update query this way:
$update = $db1->prepare("UPDATE users SET active=:active WHERE email=:email AND hash=:hash");

Your new parameters are not bound correctly, change:
$update = $db1->prepare("UPDATE users SET active=? WHERE email=? AND hash=? AND active = ?");
To:
$update = $db1->prepare("UPDATE users SET active=:active WHERE email=:email AND hash=:hash");
EDIT - Full Update Code:
$update = $db1->prepare("UPDATE users SET active=:active WHERE email=:email AND hash=:hash");
$update->bindParam(':active', $accountActive);
$update->bindParam(':email', $accountemail);
$update->bindParam(':hash', $accounthash);
$update->execute();

Related

PHP login not working. Using password_verify and it seems to be causing some problems

I am not sure why it won't work.
Login.php
$email = $_POST['email];
$password = $_POST['password];
$validEmail = filter_var($email, FILTER_VALIDATE_EMAIL);
$getpassword = $connect->query("SELECT password FROM users WHERE email = '$validEmail'");
$row = $getpassword->fetch_assoc();
All of the above works fine. I get the password which the email is connected to, so that I can "verify" the password.
$passVarify = password_varify($password, $row['password']);
When I try to "echo" out or use "var_dump" / "print_r" on "$passVerify", it just shows the number "1"?
After I have verified the password, I run another query, so that I can get the "userid" and "privileges". I needed to "unhash" or turn the password "normal" again, so that I could make the query below.
$result = $objConnection->query("SELECT userid, privileges FROM users WHERE email = '$validEmail' && password = '$passVarify'");
The code below doesn't seem to pick up the query? It just doesn't work for some reason.
if($result->num_rows > 0) {
$row = $result->fetch_assoc();
$userid = $_SESSION['userid'] = $row['userid'];
$privileges = $_SESSION['privileges'] = $row['privileges'];
}
Any good ideas? Cause I've been scratching the back of my head trying to figure out why the first "query" works and the second doesn't?!
You are making life difficult for yourself.
First the result of a password_verify() is TRUE or FALSE i.e. verified or not verified. It does not UNHASH the password. Nothing should be able to unhash a hash.
Also you dont need to do 2 seperate calls to get data from your database.
You also dont need to copy the email address from the POST array into a scalar variable.
So this would be a simpler flow for your code
Also you do not really need to filter your users entered password. If it is not right, the verify_password() will fail and that is all you need to know.
$result = $connect->query("SELECT userid, privilages, password
FROM users
WHERE email = '{$_POST['email']}'");
$user = $result->fetch_assoc();
if ( ! password_verify($_POST['password'], $user['password']) ) {
// show the password error screen
exit;
} else {
// save all the SELECTED user info into a sub array of SESSION
// to be used later
$_SESSION['user'] = $user;
}
You should really be using parameterised queries instead of injecting POST variables into a query.
$stmt= $connect->query("SELECT userid, privilages, password
FROM users
WHERE email = ?");
$stmt->bind_param("s", $_POST['email']);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_array(MYSQLI_ASSOC);

Verifying Email Confirmation

I'm having a problem getting users accounts to verify. I get it to insert data and then send out a confirmation link but when it's clicked in the email it doesn't update the 'active' row from 0 to 1. I'm been messing with this all night and it's probably something simple but either way if anyone can help I'd greatly appreciate it.
Also if anyone could provide any tips on making this injection proof I'd also be very happy. Thanks!
<?php
require ('classes/class.db.php');
require ('classes/class.pass.php');
try {
if(isset($_GET['email']) && !empty($_GET['email']) AND isset($_GET['email_hash']) && !empty($_GET['email_hash'])){
// Verify data
$search = "SELECT email, email_hash, active FROM users WHERE email='".$email."' AND hash='".$email_hash."' AND active='0'";
$match = $db->num_rows( $query );
if($match > 0){
$stmt = $db->prepare('UPDATE users (active) VALUES (:active) WHERE active = 0');
$status = $stmt->execute(array(
':active' => 1));
if( $status )
{
echo '<p>Your account has been activated, you can now login</p>';
}
}
}else{
echo '<p>Your account is already activated</p>';
}
} catch (PDOException $e) {
die($e->getMessage());
}
?>
UPDATE #1
Tried what Akam suggested but still am getting some errors. Here is what I have for my statement.
$stmt = $db->prepare("UPDATE users SET active ='1' where active = '0' and email=:email AND email_hash=:email_hash");
$status = $stmt->execute(array(
':email' => $_GET['email'],
':email_hash' => $_GET['email_hash']
));
UPDATE #2
Seems like the problem is $_GET['email_hash'] which can't be echoed or stored in a variable. It won't take the random hash string from the signup.php page and carry it over to the verify.php page, but the email address carries over perfectly fine. I'm a bit confused and would love for someone to clarify this for me. Thanks.
UPDATE #3
Problem was as simple as turning $_GET['email_hash'] to $_GET['hash'] . Thanks again!
You can also do all by one query, no need to first query if you write same conditions in the update:
"UPDATE users SET active ='1' where active = '0' and email=:email AND hash=:email"
Your UPDATE query contains a syntax error. Try changing the query to
$stmt = $db->prepare('UPDATE users SET active=:active WHERE active=0 AND email=:email AND email_hash=:email_hash');
And then include $email and $email_hash in your associative array during statement execution.
Just as a side note, calling isset($var) && !empty($var) is roughly equivalent to writing !empty($var). As per the documentation, because
empty($var)
is congruent to
!isset($var) || $var == false,
it follows that !empty($var) is congruent to isset($var) && $var != false.

Why isn't the mysql database updating in this case?

I have this PHP script:
require_once('global.php'); //connects to db and various functions used
//select the user's information
$statement = $db->prepare("SELECT * FROM user WHERE id=1");
$statement->execute();
$result = $statement->fetchObject();
//get the chat
$string = $result->chats;
$from = $_REQUEST['from'];
$msg = $_REQUEST['msg'];
$sent = $_REQUEST['sent'];
//see what we should do with the recieved data
if($string == "") {
//there isnt any chats right now, we must add the first ever contact
$string = "<ResultSet><chats><chat><messages><sms><from>{$from}</from><msg>{$msg}</msg><sent>{$sent}</sent></sms></messages><contact>{$from}</contact></chat></chats></ResultSet>";
//send the data back to the user's row in the database
$statement = $db->prepare("UPDATE user SET chats='{$string}' WHERE id=1");
$statement->execute();
} else if($from == $result->name) {
//the user is sending a message to a contact. we now need to get the "to" value.
$to = trim(str_replace("_", " ", $_REQUEST['to']));
//add the sms to the contact's chat
$string = str_replace("</sms></messages><contact>{$to}</contact>", "</sms><sms><from>{$from}</from><msg>{$msg}</msg><sent>{$sent}</sent></sms></messages><contact>{$to}</contact>", $string);
//send the data back to the user's row in the database
$statement = $db->prepare("UPDATE user SET chats='{$string}' WHERE id=1");
$statement->execute();
} else if(strstr($string, "<contact>".$from."</contact>")) {
//The contact that sent the message already exists in this user's row, add the message to the contact's chat
$string = str_replace("</sms></messages><contact>{$from}</contact>", "</sms><sms><from>{$from}</from><msg>{$msg}</msg><sent>{$sent}</sent></sms></messages><contact>{$from}</contact>", $string);
//send the data back to the user's row in the database
$statement = $db->prepare("UPDATE user SET chats='{$string}' WHERE id=1");
$statement->execute();
} else {
//Person who sent the message doesnt exist in the chats, add him.
$string = str_replace("</chats>", "<chat><messages><sms><from>{$from}</from><msg>{$msg}</msg><sent>{$sent}</sent></sms></messages><contact>{$from}</contact></chat></chats>", $string);
//send the data back to the user's row in the database
$statement = $db->prepare("UPDATE user SET chats='{$string}' WHERE id=1");
$statement->execute();
}
The problem is in this else if code:
else if($from == $result->name) {
//the user is sending a message to a contact. we now need to get the "to" value.
$to = trim(str_replace("_", " ", $_REQUEST['to']));
//add the sms to the contact's chat
$string = str_replace("</sms></messages><contact>{$to}</contact>", "</sms><sms><from>{$from}</from><msg>{$msg}</msg><sent>{$sent}</sent></sms></messages><contact>{$to}</contact>", $string);
//send the data back to the user's row in the database
$statement = $db->prepare("UPDATE user SET chats='{$string}' WHERE id=1");
$statement->execute();
}
I am sure the code is running through this else, I have echo'd and confirmed. When I use the $string = str_replace(), I printed the $string and it had indeed replaced. But when I submit the data to the row in the database, nothing happens when I refresh my db. Why does it not work for this else but does for the rest of the if statement (and the if before it)?
It doesn't make sense to me. The code I tried my best to comment it appropriately, if you need something explained just ask.
In case $db is not an instance of MySQLi or PDO but a db wrapper, look at the class that is instantiated as $db and make sure it doesn't start a transaction. If there is a transaction initiated, you will need to commit the transaction so that the changes to the database are applied/saved.
I'm not sure why but I had to change my code up so Iwould send the variables in the execute function instead of in the query. In the query I would put "?" where I want the variables, and in the execute() function I would put an array like
$statement->execute(array($string, 1));
That seems to have fixed my problem.

validating user/updating table

I have simple reset password structure for users to update their existing passwords if lost. The user goes to a link where they enter their email, a token is created and stored in a designated table for the user with the forgotten password. A email is sent to the user with a link that has the token attached, when they hit that link it takes them to a page to reset their password. If the token stored in the db matches the one in the $_GET, I allow them to reset their password. simple.
The problem is I can't update their specific row in the db. I am trying to identify them by checking their email they entered against their email in the db. I am able to update the WHOLE tables password row, but when specify one user it fails.
if(isset($_POST['sub_settings'])){
$query = "SELECT * FROM `Password_Reset` WHERE `token` = '".$token."' AND `email` = '".$user_email."'";
$request = mysql_query($query,$connection) or die(mysql_error());
$result = mysql_fetch_array($request);
$token = $result['token'];
$alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcedfghijklmnopqrstuvwxyz1234567890";
$rand = str_shuffle($alpha);
$salt = substr($rand,0,40);
$hashed_password = sha1($salt . $_POST['password']);
$user_email = $result['email'];
if($_GET['token'] == $token) {
header("Location: index.php");
exit;
}else{
if(empty($_POST['Password'])) {
$valid = false;
$error_msgs[] = 'Whoops! You must enter a password.';
}
if($_POST['Password'] != $_POST['passwordConfirm'] || empty($_POST['Password'])) {
$valid = false;
$error_msgs[] = "Your password entries didn't match...was there a typo?";
}
if($valid) {
$query = "UPDATE `Users` SET `encrypted_password` = '$hashed_password' WHERE `Email` = '$user_email'";
mysql_query($query,$connection);
}
}
}
Thanks so much in advance
Why don't you store the user id in the Password_Reset table and then update the user based on there id rather than trying to match there email.
Note that if you are trying to match the users email the email casing must match exactly with an '=' in the query. You could lowercase the email address but this is technically incorrect.
$query = "
SELECT *
FROM `Password_Reset`
WHERE `token` = '".$token."' AND LOWER(`email`) = LOWER('".$user_email."')
";
It looks like you've not capitalized $_POST['Password']
$hashed_password = sha1($salt . $_POST['password']);
Based on your other code, it should be:
$hashed_password = sha1($salt . $_POST['Password']);
Also in your SELECT, you have email and in your UPDATE you use Email. MySQL is case-sensitive by default on non-windows platforms.
It looks like you have $user_email in your first query but it's not set yet because you're setting it with the result of the first query. Unless you mean $_POST['user_email']?
It would be MUCH easier and more secure to use a user_id and only send the user a token if they are actually in your system (it appears you're sending everyone a token!)
Your token should be unique. It looks like it's completely random. A good way to make a token is to create a random string + something that uniquely identifies the user (such as their username or email) and then use MD5 or a similar function to hash it. It's reasonably secure and it identifies the user themselves so you can look them up by the token only.
if($_GET['token'] == $token) {
header("Location: index.php");
exit;
Should be != I suppose.
You need to check if the token is not equal to the token into db. Isn't it?

Storing info in a PostgreSQl database issue

Ok I am making a registry for my website.
First page asks for some personal info
if($error==false) {
$query = pg_query("INSERT INTO chatterlogins(firstName, lastName, gender, password, ageMonth, ageDay, ageYear, email, createDate) VALUES('$firstNameSignup', '$lastNameSignup', '$genderSignup', md5('$passwordSignup'), $monthSignup, $daySignup, $yearSignup, '$emailSignup', now());");
$query = pg_query("INSERT INTO chatterprofileinfo(email, lastLogin) VALUES('$emailSignup', now());");
$userNameSet = $emailSignup;
$_SESSION['$userNameSet'] = $userNameSet;
header('Location: signup_step2.php'.$rdruri);
}
The first query works. The second query works but doesn't save the email...
the session doesn't work but the header works and sends me to the next page
I get no errors even if I comment out header
next page
#session_start();
$conn = pg_connect("host=localhost dbname=brittains_db user=brittains password=XXXX" );
$signinCheck = false;
$checkForm = "";
if(isset($_SESSION['$userName'])) {
$userName = $_SESSION['$userName'];
$signinCheck = true;
$query = pg_query("UPDATE chatterprofileinfo SET lastLogin='now()' WHERE email='$userName'");
}
if(isset($_SESSION['$userNameSet'])) {
$userName = $_SESSION['$userNameSet'];
$signinCheck = true;
$query = pg_query("UPDATE chatterprofileinfo SET lastLogin='now()' WHERE email='$userName'");
}
This is the top starting the session depending on if your logged in or not.
then if I enter in the info here and put it through this
if($error==false) {
$query = pg_query("UPDATE chatterprofileinfo SET aboutSelf='$aboutSelf', hobbies='$hobbies', music='$music', tv='$tv', sports='$sports', lastLogin='now()' WHERE email='$userName'") or exit(pg_last_error());
//header('Location: signup_step3.php'.$rdruri);
}
nothing shows up for on my database from this.
I have no idea where I went wrong
the website is
http://opentech.durhamcollege.ca/~intn2201/brittains/chatter/
For starters, don't put things that aren't strings in single-quotes like that. 'now()' means a literal string "now()"
Also, if you're doing updates to your database you're better of using prepared statements to help prevent against sql injection. In your case, see http://www.php.net/manual/en/function.pg-prepare.php

Categories