patternphpMinor
Password recovery program
Viewed 0 times
recoveryprogrampassword
Problem
This is a password recovery program I made, and I just want it checked out.
These aren't all the files for the login and register system, only the password recovery part. The columns in the
```
query("SELECT * FROM users WHERE username = '".$con->real_escape_string($us)."' LIMIT 1");
if ($query->num_rows === 1) {
$row = $query->fetch_assoc();
if (isset($row['passres'], $row['passexp'])) {
if (hash('sha256', $key) == $row['passres']) {
if ($row['passexp'] query("UPDATE users SET passres = NULL
These aren't all the files for the login and register system, only the password recovery part. The columns in the
users table are id, username, password, salt, passres, and passexp. passres is the reset token, and passexp is the expiration time for the url. I know I am supposed to mail them the link and not just show it to them, but I don't have an email server, so that is what I am doing to test it.resetpass.php:query("SELECT * FROM users WHERE username = '".$con->real_escape_string($us)."' LIMIT 1");
if ($query->num_rows === 1) {
$row = $query->fetch_assoc();
do {
$key = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()-_=+|[]{}:<>./?"), 0, 50);
} while($con->query("SELECT passres FROM users WHERE passres = '".$con->real_escape_string($key)."'")->num_rows > 0);
$hash = hash('sha256', $key);
$date = time() + 172800;
if ($con->query("UPDATE users SET passres = '".$con->real_escape_string($hash)."', passexp = '".$con->real_escape_string($date)."' WHERE id = ".$con->real_escape_string($row['id']))) {
echo 'http://localhost/login/reset.php?key='.$key.'&user='.urlencode($row['username']).'';
} else {
echo ('An error occured.');
}
} else {
header('Location:'); exit();
}
} else {
?>
reset.php:```
query("SELECT * FROM users WHERE username = '".$con->real_escape_string($us)."' LIMIT 1");
if ($query->num_rows === 1) {
$row = $query->fetch_assoc();
if (isset($row['passres'], $row['passexp'])) {
if (hash('sha256', $key) == $row['passres']) {
if ($row['passexp'] query("UPDATE users SET passres = NULL
Solution
Security practices and correctness
It's probably a good idea to keep an audit log of the times and client IP addresses for all attempted and completed password changes.
`
It's probably a good idea to keep an audit log of the times and client IP addresses for all attempted and completed password changes.
`
and are vulnerable to cross-site scripting (or HTML injection) attacks. You should take care to call htmlspecialchars(…) whenever emitting HTML.
Instead of , you should use , which is more straightforward. In fact, some browsers have been known to not submit those display: none form fields at all, due to an implementation bug or misinterpretation of the CSS specification.
Salted MD5 and SHA hashes are no longer considered good password-storage mechanisms. If you have PHP ≥ 5.5.0, you should use password_hash(), which uses the bcrypt algorithm.
Implementation
There is also a lot of related code between resetpass.php and reset.php, such as the passres generator and verifier, that should be extracted into functions and placed in a file that is included by both pages.
The indentation in reset.php` is very deep. Keeping in mind that this usually one way to succeed but many ways to fail, it would help to invert your conditions such that the error handler comes first.if (query->num_rows fetch_assoc();
if (!isset($row['passres'], $row['passexp']) ||
hash('sha256', $key) != $row['passres']) {
header('HTTP/1.0 404 Not Found');
exit();
} elsif ($row['passexp'] <= time()) {
echo 'This link has expired!';
…
exit();
}
$pass = …;
…Code Snippets
if (query->num_rows < 1) {
header('HTTP/1.0 404 Not Found');
exit();
}
$row = $query->fetch_assoc();
if (!isset($row['passres'], $row['passexp']) ||
hash('sha256', $key) != $row['passres']) {
header('HTTP/1.0 404 Not Found');
exit();
} elsif ($row['passexp'] <= time()) {
echo 'This link has expired!';
…
exit();
}
$pass = …;
…Context
StackExchange Code Review Q#99312, answer score: 5
Revisions (0)
No revisions yet.