Verification link not activating account - php

So I've sent a link after registration to Verify an account, the link contains the users email address and a 32 character code for example:
$to = $email;
$subject = 'Signup | Verification';
$message = '
Thanks for signing up!
Your account has been created, you can login with the following credentials after you have activated your account by pressing the url below.
------------------------
Username: '.$username.'
Password: '.$password.'
------------------------
Please click this link to activate your account:
localhost:8888/website/verify.php?email='.$email.'&hash='.$hash.'
';
$headers = 'From:myemail#email.com' . "\r\n";
mail($to, $subject, $message, $headers);
That all seems to work fine I'm receiving the email with a link like this:
http://localhost:8888/website/verify.php?email=myemail#email.com&hash=fe646d38bc2145ca6c3cf77d52820cd0
The problem comes when I follow the link and try to activate the account. It takes me to Verify.php fine but I keep getting Invalid Approach and I'm unable to set Validation to 1.
<?php include "includes/base.php"; ?>
<?php
if(isset($_GET['Email']) && !empty($_GET['Email']) AND isset($_GET['Hash']) && !empty($_GET['Hash'])){
$email = mysql_escape_string($_GET['Email']);
$hash = mysql_escape_string($_GET['Hash']);
$search = mysql_query("SELECT Email, Hash, Validation FROM users WHERE Email = '".$email."' AND Hash = '".$hash."' AND Validation = 0") or die(mysql_error());
$match = mysql_num_rows($search);
if($match > 0){
mysql_query("UPDATE users SET Validation = 1 WHERE Email = '".$email."' AND Hash = '".$hash."' AND Validation = 0") or die(mysql_error());
echo "Your account has been activated, you can now login";
}else{
echo "The url is either invalid or you already have activated your account.";
}
}else{
echo "Invalid approach, please use the link that has been sent to your email.";
}
?>

1) this code is unsecure as it has SQL injection problem. Use prepared statements
Please keep in mind that mysql_* functions are no longer supported and they are depriated
2) Regarding your code I found that your GET request has 'email' and 'hash' all lowercase, but in PHP code you use $_GET['Email'] and $_GET['Hash'].
You need to change this:
if(isset($_GET['Email']) && !empty($_GET['Email']) AND isset($_GET['Hash']) && !empty($_GET['Hash'])){
$email = mysql_escape_string($_GET['Email']);
$hash = mysql_escape_string($_GET['Hash']);
To this
if(isset($_GET['email']) && !empty($_GET['email']) AND isset($_GET['eash']) && !empty($_GET['eash'])){
$email = mysql_escape_string($_GET['email']);
$hash = mysql_escape_string($_GET['eash']);
or change your GET request to the next one:
http://localhost:8888/website/verify.php?Email=myemail#email.com&Hash=fe646d38bc2145ca6c3cf77d52820cd0

Change Hash to hash & Email to email. (Capitalized, but not in link that you send)
Also, your code is prone to sql injection attack as you are directly using the values in the url to query your database. Please use mysql_real_escape_string and perform some sanity checks before making the query.

there's capitals in the PHP whereas there are none in the link
$_GET['Email']
verify.php?email=myemail#email.com

Related

Why is the else statement not working inside a foreach loop in php?

I'm building a script that helps a user reset their password if they forgot it. This specific script firstly checks if the email the user wants the token sent to exists. If it does, the token is inserted into a tokens table.
I am still developing and testing, so I haven't created the mail function yet.
I have an if statement that checks if the email exists, then creates the token. If it doesn't exists, it shows the page to enter an email address again. The if statement is working perfect, but the else is not. I'm pasting the entire file here, though it is only the part with the foreach statement that concerns our problem.
The else statement shows absolutely nothing.
<?php
//generate tokens to verify users who forgot their passwords. Send these tokens to the user's email
require $_SERVER['DOCUMENT_ROOT'] . "/phonebook/config.php";
//get user's email
$mail = htmlspecialchars($_POST['email']);
//generate token
$token = $token = openssl_random_pseudo_bytes(20);
//Convert the binary data into something more readable
$token = bin2hex($token);
//check if the email entered exists
$check = $conn->prepare("SELECT email FROM users WHERE email = :email");
$check->bindParam(":email", $mail);
$check->execute();
foreach ($check as $confirm) {
if ($confirm['email'] == $mail) {
//send tokens to the database
$sql = $conn->prepare("INSERT INTO tokens (email, token)
VALUES(:email, :token)");
$sql->bindParam(":email", $mail);
$sql->bindParam(":token", $token);
$sql->execute();
echo "<h2>Enter security code</h2>
A security code has been sent to the email addres $mail. Enter that code in the box below:
<form action = 'http://localhost/phonebook/controls/forgotpassword.php' method = 'post'>
<input type = 'hidden' name = 'email' value = '$mail'>
<input type = 'text' name = 'token'> <br>
<input type = 'submit' value = 'Reset password'>
</form>
Did not receive code? Go <a href = 'http://localhost/pages/forgotpassword.php'here</a>";
} else {
echo "That email does not exist. Please try again.";
include_once "$paste/phonebook/pages/forgotpassword.php";
}
}
Spotting three problems here.
You compare $mail which is encoded using htmlspecialchars() against an email address which is probably not encoded.
You fetch several rows instead of one:
//check if the email entered exists
$check = $conn->prepare("SELECT email FROM users WHERE email = :email LIMIT 1");
$check->bindParam(":email", $mail);
$check->execute();
$confirm = $check->fetch()
if (isset($confirm['email']) && $confirm['email'] === $mail) {
//send tokens to the database
You tell the "user" that the email address does exist in your system; this is a privacy and data security concern. Just send something like "If the entered email address is in our system, we just sent a password reset link to it."

Broken register after setting up SSL

Basically I set up a self signed SSL certificate and all of a sudden my register forum stopped working, it almost feels as if it goes into a redirect loop but it doesn't, the way my register works is that you need to verify you account by email. When you click the register, the page doesn't load for a couple of minutes and then it eventually gives you the notification that the verification sent but it doesn't send to your email address. Also before I set up the self signed SSL it did work, I believe it's because SSL doesn't see my register.php forum as secure therefor it doesn't send it because it's uncrypted, if there is a bypass or a way to fix this it would be greatly appreciated.
<?php
define('DIRECT', TRUE);
function getRealIpAddr()
{
if (!empty($_SERVER['HTTP_CLIENT_IP'])) //check ip from share internet
{
$ip=$_SERVER['HTTP_CLIENT_IP'];
}
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //to check ip is pass from proxy
{
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$ip=$_SERVER['REMOTE_ADDR'];
}
return $ip;
}
/* Registration process, inserts user info into the database
and sends account confirmation email message
*/
// Set session variables to be used on activate.php page
$_SESSION['email'] = $_POST['email'];
$_SESSION['username'] = $_POST['firstname'];
// Escape all $_POST variables to protect against SQL injections
$username = $mysqli->escape_string($_POST['firstname']);
$ip=$_SERVER['REMOTE_ADDR'] = getRealIpAddr();
$dateTime = date('Y/m/d G:i:s');
$email = $mysqli->escape_string($_POST['email']);
$uncryptpass = $mysqli->escape_string($_POST['password']);
$password = $mysqli->escape_string(password_hash($_POST['password'], PASSWORD_BCRYPT));
$hash = $mysqli->escape_string( md5( rand(0,1000) ) );
// Check if user with that email already exists
$result = $mysqli->query("SELECT * FROM users WHERE email='$email'") or die($mysqli->error());
// We know user email exists if the rows returned are more than 0
if ( $result->num_rows > 0 ) {
$_SESSION['message'] = 'An account with ' .$email. ' already exists!';
header("location: /login/index.php");
}
else { // Email doesn't already exist in a database, proceed...
// active is 0 by DEFAULT (no need to include it here)
$sql = "INSERT INTO users (username, email, uncryptpass, password, hash, ip, date) "
. "VALUES ('$username','$email','$uncryptpass','$password', '$hash', '$ip', '$dateTime')";
// Add user to the database
if ( $mysqli->query($sql) ){
$_SESSION['active'] = 0; //0 until user activates their account with verify.php
$_SESSION['logged_in'] = true; // So we know the user has logged in
$_SESSION['message'] =
"Confirmation link has been sent to $email, please verify
your account by clicking on the link in the message!";
// Send registration confirmation link (verify.php)
$to = $email;
$subject = 'Account Verification';
$message_body = '
'.$username.',
***DO NOT RESPOND BACK TO THIS EMAIL***
https://example.com/login/verify.php?email='.$email.'&hash='.$hash;
mail( $to, $subject, $message_body );
header("location: activate.php");
}
else {
$_SESSION['message'] = 'Registration failed!';
header("location: /login/index.php");
}
}

undefined index on $_SESSION and all $_POST part

I want to make register form for my website. But I faced error and this is my code:
<?php
/* Registration process, inserts user info into the database
and sends account confirmation email message
*/
// Set session variables to be used on profile.php page
$_SESSION['email'] = $_POST['email'];
$_SESSION['first_name'] = $_POST['firstname'];
$_SESSION['last_name'] = $_POST['lastname'];
$mysqli = mysqli_connect("localhost","root","","data");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
// Escape all $_POST variables to protect against SQL injections
$first_name = $mysqli->escape_string($_POST['firstname']);
$last_name = $mysqli->escape_string($_POST['lastname']);
$email = $mysqli->escape_string($_POST['email']);
$password = $mysqli->escape_string(password_hash($_POST['password'],
PASSWORD_BCRYPT));
$hash = $mysqli->escape_string( md5( rand(0,1000) ) );
// Check if user with that email already exists
$result = $mysqli->query("SELECT * FROM login WHERE email='$email'") or
die($mysqli->error());
// We know user email exists if the rows returned are more than 0
if ( $result->num_rows > 0 ) {
$_SESSION['message'] = 'User with this email already exists!';
header("location: error.php");
}
else { // Email doesn't already exist in a database, proceed...
// active is 0 by DEFAULT (no need to include it here)
$sql = "INSERT INTO login (first_name, last_name, email, password, hash)"
."VALUES ('$first_name','$last_name','$email','$password', '
$hash')";
// Add user to the database
if ( $mysqli->query($sql) ){
$_SESSION['active'] = 0; //0 until user activates their account with
verify.php
$_SESSION['logged_in'] = true; // So we know the user has logged in
$_SESSION['message'] =
"Confirmation link has been sent to $email, please verify
your account by clicking on the link in the message!";
// Send registration confirmation link (verify.php)
$to = $email;
$subject = 'Account Verification ( clevertechie.com )';
$message_body = '
Hello '.$first_name.',
Thank you for signing up!
Please click this link to activate your account:
http://localhost/login-system/verify.php?email='.$email.'&
hash='.$hash;
mail( $to, $subject, $message_body );
header("location: profile.php");
}
else {
$_SESSION['message'] = 'Registration failed!';
header("location: error.php");
exit();
}
}
The error state that:
Undefined index: firstname, lastname, email, password
at line set session variables and line for escape all $_POST variables to protect SQL injection. Anyone know how to fix this error. Thank you.
You are missing session_start() at the start of your code, this needs to be called before you echo/output anything to the browser.
You'll also need to add session_start to your error.php to read from the session there.
When session_start() is called or when a session auto starts, PHP will call the open and read session save handlers...
The read callback will retrieve any existing session data (stored in a special serialized format) and will be unserialized and used to automatically populate the $_SESSION superglobal when the read callback returns the saved session data back to PHP session handling.
See: http://php.net/manual/en/function.session-start.php
If(isset($_POST['first_name']) && isset($_POST['last_name']) && isset($_POST['email'])){
// Escape all $_POST variables to protect against SQL injections
$first_name = $mysqli->escape_string($_POST['firstname']);
$last_name = $mysqli- >escape_string($_POST['lastname']);
}
In PHP, a variable or array element which has never been set is different from one whose value is null; attempting to access such an unset value is a runtime error.
That's what you're running into: the array $_POST does not have any element at the index "username", so the interpreter aborts your program before it ever gets to the nullity test.

Sign up script security check

Hey guys, I have this sign up script and I'm using mysql_real_escape_string .I know prepared statements are safer but I'm just not experienced enough to use them, I just can't figure out how. Anyway here's the script:
<?php
$username=mysql_real_escape_string($_POST['username']);
$password=sha1($_POST['password']);
$password2=sha1($_POST['password_confirmation']);
$passcheck=$_POST['password'];
$todo=mysql_real_escape_string($_POST['todo']);
$email=mysql_real_escape_string($_POST['email']);
$fname=mysql_real_escape_string($_POST['fname']);
$lname=mysql_real_escape_string($_POST['lname']);
$gender=$_POST['gender'];
$class=$_POST['class'];
$section=$_POST['section'];
if(isset($todo) and $todo=="post"){
$status = "OK";
$msg="";
}
if(!isset($username) OR strlen($username) <3){
$msg=$msg."Username should be equal to or more than 3 characters long.<BR/>";
$status= "NOTOK";
}
if(mysql_num_rows(mysql_query("SELECT username FROM users WHERE username = '$username'"))){
$msg=$msg."Username already exists. Please try another one.<BR/>";
$status= "NOTOK";
}
if(mysql_num_rows(mysql_query("SELECT email FROM users WHERE email = '$email'"))){
$msg=$msg."E-mail is already in use. Please try again.<BR/>";
$status= "NOTOK";
}
if ( strlen($passcheck) < 3 ){
$msg=$msg."Password must be more than 3 charactors long.<BR/>";
$status= "NOTOK";
}
if ( $password <> $password2 ){
$msg=$msg."Passwords are not identical.<BR/>";
$status= "NOTOK";
}
if(!eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $email)){
$msg=$msg."The email is not a valid email.<br/>";
$status="NOTOK";
}
if($status=="NOTOK"){
echo '<div class="statusmsg">'.$msg.'<br/><input class="submitButton" type="button" value="Retry" onClick="location.href='."'signup.php'\"></div>";
}
else {
$hash = md5( rand(0,1000) );
$hash = mysql_real_escape_string($hash);
if(mysql_query("insert into users(username,password,email,fname,lname,hash,gender,class,section) values('$username','$password','$email','$fname','$lname','$hash','$gender','$class','$section')")or die (mysql_error ())){
echo '<div class="statusmsg">Welcome, You have successfully signed up. Please check the verification e-mail sent to you.</div>';
$to = $email;
$subject = 'Signup | Verification';
$message = '
Thanks for signing up!
Your account has been created, you can login with the following credentials after you have activated your account by pressing the url below.
------------------------
Username: '.$username.'
------------------------
Please click this link to activate your account:
<div id="header">
<h3>JMToday > Sign up</h3>
</div>
http://www.JMtoday.com/verification.php?email='.$email.'&hash='.$hash.'
';
$headers = 'From:noreply#JMtoday.com' . "\r\n";
mail($to, $subject, $message, $headers);
}
else {
echo "Database problem, please contact site admin";
}
}
?>
The user will never see the "database problem" message, as the script will die() out if the query fails. As well, you're embedding HTML into the message, but are not building a proper HTML-format email. Some mail clients may be smart enough to figure out there's HTML and render it as such, but that's just luck.
The hash you generate is limited to generating only 1001 hashes. Given the birthday paradox, after 38 people sign up, the odds of a collision are 50%. After 100 people, the odds are 99.29%. Instead of hashing a random number, do something like:
$hash = md5(serialize($_POST) . $some_other_stuff_in_case_POST_is_empty);

Creating a mechanism to validate emails

I already have an advanced user login/register system on my website (colemansystems.psm2.co.uk). However, I would like to have a email sent to new users for verification of their email address. If they have not clicked the link they will not be able to access their account. I am semi-experienced with PHP and MySQL, so please explain in depth.
The code I'm using for the verify.php file (the link the user click on with a GET (for example, verify.php?d=51773199320))
$secret = $_GET['d'];
$result = mysql_query("SELECT valid FROM users WHERE secret=$secret");
while ($row = mysql_fetch_array($result))
{
$valid = $row['valid'];
}
if ($valid == "") {
echo"There seems to be a problem with the verification code.<br><br><br><br><br>";
}
elseif ($valid == "1")
{
echo"Your account is already verified.<br><br><br><br><br>";
}
else
{
mysql_query("UPDATE users SET valid = '1' WHERE secret=$secret");
echo "Thank you, your account is now verified and you are free to use the exclusive features!<br><br><br><br><br><br>";
}
Is this secure?
The easiest way is not to register unverified users at all.
Ask them for an email address and send email with a link that contains this address sealed with a hash. Upon receiving this link you can start the registration process.
Something like this
$secret = "35onoi2=-7#%g03kl";
$email = urlencode($_POST['email']);
$hash = MD5($_POST['email'].$secret);
$link = "http://example.com/register.php?email=$email&hash=$hash";
And in your register.php add 2 hidden fields to the registration form - email and hash, storing their received values from GET.
Finally, process registration and check,
if (md5($_POST['email'].$secret) == $_POST['hash']) {
//Continue registration.
}
Easiest for whom - user, coder, computer?
What are you optimizing - the quantity of keypresses, the size of the code, the user experience?
The easiest to code is probably unsafe.
You should check the email address for correctness before sending a letter to it.
after registration create a hashed string and save it to the temporary user table send that hashed string to the user email address using this code
if(isset($_POST['register']))
{
$email_id=$_POST['email'];
$pass=$_POST['password'];
$code=substr(md5(mt_rand()),0,15);
mysql_connect('localhost','root','');
mysql_select_db('sample');
$insert=mysql_query("insert into verify values('','$email','$pass','$code')");
$db_id=mysql_insert_id();
$message = "Your Activation Code is ".$code."";
$to=$email;
$subject="Activation Code For Talkerscode.com";
$from = 'your email';
$body='Your Activation Code is '.$code.' Please Click On This link Verify.php?id='.$db_id.'&code='.$code.'to activate your account.';
$headers = "From:".$from;
mail($to,$subject,$body,$headers);
echo "An Activation Code Is Sent To You Check You Emails";
}
and after that create a verify page and then
if(isset($_GET['id']) && isset($_GET['code']))
{
$id=$_GET['id'];
$code=$_GET['id'];
mysql_connect('localhost','root','');
mysql_select_db('sample');
$select=mysql_query("select email,password from verify where id='$id' and code='$code'");
if(mysql_num_rows($select)==1)
{
while($row=mysql_fetch_array($select))
{
$email=$row['email'];
$password=$row['password'];
}
$insert_user=mysql_query("insert into verified_user values('','$email','$password')");
$delete=mysql_query("delete from verify where id='$id' and code='$code'");
}
}
if you have any problem here is a complete tutorial http://talkerscode.com/webtricks/account-verification-system-through-email-using-php.php

Categories