PHP password-resetting page I am producing a PHP code and I want to implement it in my server to do its function. My question is, are there any vulnerabilities that I should correct?

I tried to establish the session first then I will initiate a SQL connection and I will ask the user to enter his email. Also I added the reset function of his email.

&lt;?php
if ($_SESSION['admin'] !== true) {
    header('Location: /login.php?');
}

$conn = new mysqli("localhost","admin","password","db");

if ($conn-&gt;connect_error) {
    die("Connection failed: " . $conn-&gt;connect_error);
}

$msg = '';
if (isset($_POST['submit'])) {
    $email = $_POST['email'];
    $sql = "SELECT * FROM users WHERE email = $email;";
    $result = @$conn-&gt;query($sql);
    if ($result-&gt;num_rows == 0) {
        die("This email: $email is incorrect");
    }
    $row = $result-&gt;fetch_assoc();
    $id = $row["id"];
    $surename = $row["surename"];

    $sql = "SELECT * from users JOIN password_resets ON (password_resets.user_id=users.id)  WHERE id=$id;";
    $result = @$conn-&gt;query($query);
    if ($result-&gt;num_rows == 0) {
        $insert_sql = "INSERT INTO password_resets (user_id, reset_timestamp) VALUES ($id, unix_timestamp());";
        if ($conn-&gt;query($insert_sql) !== TRUE) {
            die("Error: " . $insert_sql . "&lt;br&gt;" . $conn-&gt;error);
        }
    }
    $result = $conn-&gt;query($query);
    $row = $result-&gt;fetch_assoc();

    $link = "https://".$_SERVER['SERVER_NAME']."/reset.php?id=".$row['id'] ."&amp;timestamp=".$row['reset_timestamp'];
    $message = "Hi, $surename,

    Here's your password reset link: $link";
    $headers = "From: ".$_SESSION['first_name']." ".$_SESSION['last_name']." &lt;".$_SESSION['email']."&gt;";
    mail($email,"Your password reset link",$message,$headers);
    $msg = "Password reset for $email sent!";
?&gt;
&lt;html&gt;
&lt;head&gt;&lt;title&gt;Reset password for a user&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
  &lt;form&gt;
    &lt;div class="message"&gt;&lt;?=$msg ?&gt;&lt;/div&gt;
    &lt;input type="text" width=80 name="email"&gt;
    &lt;input type="submit" name="submit" value="Send"&gt;
  &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;
&lt;?php
}
Your code is wide open to SQL Injection which is the most dangerous web vulnerability. This occurs when you execute SQL queries with unsanitized user data. By placing the raw $_POST variable directly in your query you are allowing an attacker to inject their own SQL into your query and execute it. They can do anything from stealing data to deleting your database.

To combat this you must use parameterized queries. Stack Overflow covers this very well but here's what your code would like if you use mysqli with prepared statements:

$stmt = $dbConnection-&gt;prepare('SELECT * FROM users WHERE email = ?');
$stmt-&gt;bind_param('s', $email); // 's' specifies the variable type =&gt; 'string'

$stmt-&gt;execute();

$result = $stmt-&gt;get_result();
$row = $result-&gt;fetch_assoc();


You also are wide open to Cross-site scripting (XSS) attacks which is the #7 web vulnerability. This occurs because you take raw $_POST data and output it directly into your HTML. An attacker can place malicious code in this value and attack your users and site once it is rendered by the browser.

When outputting user data, always escape that data. Stack Overflow covers this as well. In PHP you can do this by using htmlspecialchars().

&lt;?= htmlspecialchars($msg, ENT_QUOTES, 'UTF-8'); ?&gt;


You will notice that the one $_POST variable, $_POST['email'], has left your site wide open to attack. Before you even attempt to use it you should validate it indeed is a valid email address. If it is not, you should report an error and not attempt to use it as it obviously is invalid and useless anyway.

PHP offers an easy way to validate an email addresses. filter_var() with the FILTER_VALIDATE_EMAIL flag will validate if an email address is valid. 

$email = $_POST['email'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    // email is invalid. report error and abort.
}


On a different note, you start your script off by checking to see if a user is an admin. If they are not you use header() to do a redirect away from that page. That's usually okay but you should follow it with a call to exit() to ensure the script stops executing. If not, the code below may still execute and, combined with other vulnerabilities in the page, leave you open to attack.

if ($_SESSION['admin'] !== true) {
    header('Location: /login.php?');
    exit;
}