我有更改密码的脚本:
<?php
/*
Page/Script Created by Shawn Holderfield
*/
//Establish output variable - For displaying Error Messages
$msg = "";
//Check to see if the form has been submitted
if (mysql_real_escape_string($_POST['submit'])):
//Establish Post form variables
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string(md5($_POST['password']));
$npassword = mysql_real_escape_string(md5($_POST['npassword']));
$rpassword = mysql_real_escape_string(md5($_POST['rpassword']));
//Connect to the Database Server
mysql_connect("mysql..", "", "")or die(mysql_error());
// Connect to the database
mysql_select_db("") or die(mysql_error());
// Query the database - To find which user we're working with
$sql = "SELECT * FROM members WHERE username = '$username' ";
$query = mysql_query($sql);
$numrows = mysql_num_rows($query);
//Gather database information
while ($rows = mysql_fetch_array($query)):
$username == $rows['username'];
$password == $rows['password'];
endwhile;
//Validate The Form
if (empty($username) || empty($password) || empty($npassword) || empty($rpassword)):
$msg = "All fields are required";
elseif ($numrows == 0):
$msg = "This username does not exist";
elseif ($password != $password):
$msg = "The CURRENT password you entered is incorrect.";
elseif ($npassword != $rpassword):
$msg = "Your new passwords do not match";
elseif ($npassword == $password):
$msg = "Your new password cannot match your old password";
else:
//$msg = "Your Password has been changed.";
mysql_query("UPDATE members SET password = '$npassword' WHERE username = '$username'");
endif;
endif;
?>
<html>
<head>
<title>Change Password</title>
</head>
<body>
<form method="POST" action="">
<table border="0">
<tr>
<td align="right">Username: </td>
<td><input type="TEXT" name="username" value=""/></td>
</tr>
<tr>
<td align="right">Current Password: </td>
<td><input type="password" name="password" value=""/></td>
</tr>
<tr>
<td align="right">New Password: </td>
<td><input type="password" name="npassword" value=""/></td>
</tr>
<tr>
<td align="right">Repeat New Password: </td>
<td><input type="password" name="rpassword" value=""/></td>
</tr>
<tr><td>
<input type="submit" name="submit" value="Change Password"/>
</td>
</tr>
</table>
</form>
<br>
<?php echo $msg; ?>
</body>
</html>
这实际上工作正常,访问数据库并覆盖当前密码,但它不会像注册时那样对密码进行哈希处理 注册流程脚本:
<?php
include_once 'db_connect.php';
include_once 'psl-config.php';
$error_msg = "";
if (isset($_POST['username'], $_POST['email'], $_POST['p'])) {
// Sanitize and validate the data passed in
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$email = filter_var($email, FILTER_VALIDATE_EMAIL);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
// Not a valid email
$error_msg .= '<p class="error">The email address you entered is not valid</p>';
}
$password = filter_input(INPUT_POST, 'p', FILTER_SANITIZE_STRING);
if (strlen($password) != 128) {
// The hashed pwd should be 128 characters long.
// If it's not, something really odd has happened
$error_msg .= '<p class="error">Invalid password configuration.</p>';
}
// Username validity and password validity have been checked client side.
// This should should be adequate as nobody gains any advantage from
// breaking these rules.
//
$prep_stmt = "SELECT id FROM members WHERE email = ? LIMIT 1";
$stmt = $mysqli->prepare($prep_stmt);
// check existing email
if ($stmt) {
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 1) {
// A user with this email address already exists
$error_msg .= '<p class="error">A user with this email address already exists.</p>';
$stmt->close();
}
$stmt->close();
} else {
$error_msg .= '<p class="error">Database error Line 39</p>';
$stmt->close();
}
// check existing username
$prep_stmt = "SELECT id FROM members WHERE username = ? LIMIT 1";
$stmt = $mysqli->prepare($prep_stmt);
if ($stmt) {
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 1) {
// A user with this username already exists
$error_msg .= '<p class="error">A user with this username already exists</p>';
$stmt->close();
}
$stmt->close();
} else {
$error_msg .= '<p class="error">Database error line 55</p>';
$stmt->close();
}
// TODO:
// We'll also have to account for the situation where the user doesn't have
// rights to do registration, by checking what type of user is attempting to
// perform the operation.
if (empty($error_msg)) {
// Create a random salt
//$random_salt = hash('sha512', uniqid(openssl_random_pseudo_bytes(16), TRUE)); // Did not work
$random_salt = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));
// Create salted password
$password = hash('sha512', $password . $random_salt);
// Insert the new user into the database
if ($insert_stmt = $mysqli->prepare("INSERT INTO members (username, email, password, salt) VALUES (?, ?, ?, ?)")) {
$insert_stmt->bind_param('ssss', $username, $email, $password, $random_salt);
// Execute the prepared query.
if (! $insert_stmt->execute()) {
header('Location: ../error.php?err=Registration failure: INSERT');
}
}
header('Location: ./continue.php');
}
}
?>
我该怎么做才能解决这个问题?我希望更改的密码格式与注册时一样。因为现在,当我更改密码时,它是哈希但不是+盐渍的,所以当使用新密码登录时它不起作用。
编辑: 这是登录脚本:
<?php
include_once 'psl-config.php';
function sec_session_start() {
$session_name = 'sec_session_id'; // Set a custom session name
$secure = SECURE;
// This stops JavaScript being able to access the session id.
$httponly = true;
// Forces sessions to only use cookies.
if (ini_set('session.use_only_cookies', 1) === FALSE) {
header("Location: ../error.php?err=Could not initiate a safe session (ini_set)");
exit();
}
// Gets current cookies params.
$cookieParams = session_get_cookie_params();
session_set_cookie_params($cookieParams["lifetime"],
$cookieParams["path"],
$cookieParams["domain"],
$secure,
$httponly);
// Sets the session name to the one set above.
session_name($session_name);
session_start(); // Start the PHP session
session_regenerate_id(true); // regenerated the session, delete the old one.
}
function login($email, $password, $mysqli) {
// Using prepared statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, password
FROM members
WHERE email = ?
LIMIT 1")) {
$stmt->bind_param('s', $email); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($user_id, $username, $db_password );
$stmt->fetch();
// hash the password
$passwordHash = password_hash($password, PASSWORD_BCRYPT);
if ($stmt->num_rows == 1) {
// If the user exists we check if the account is locked
// from too many login attempts
if (checkbrute($user_id, $mysqli) == true) {
// Account is locked
// Send an email to user saying their account is locked
return false;
} else {
// Check if the password in the database matches
// the password the user submitted.
if ($db_password == $password) {
// Password is correct!
// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];
// XSS protection as we might print this value
$user_id = preg_replace("/[^0-9]+/", "", $user_id);
$_SESSION['user_id'] = $user_id;
// XSS protection as we might print this value
$username = preg_replace("/[^a-zA-Z0-9_\-]+/",
"",
$username);
$_SESSION['username'] = $username;
$_SESSION['email'] = $email;
$_SESSION['login_string'] = hash('sha512',
$password . $user_browser);
// Login successful.
return true;
} else {
// Password is not correct
// We record this attempt in the database
$now = time();
$mysqli->query("INSERT INTO login_attempts(user_id, time)
VALUES ('$user_id', '$now')");
return false;
}
}
} else {
// No user exists.
return false;
}
}
}
function checkbrute($user_id, $mysqli) {
// Get timestamp of current time
$now = time();
// All login attempts are counted from the past 2 hours.
$valid_attempts = $now - (2 * 60 * 60);
if ($stmt = $mysqli->prepare("SELECT time
FROM login_attempts
WHERE user_id = ?
AND time > '$valid_attempts'")) {
$stmt->bind_param('i', $user_id);
// Execute the prepared query.
$stmt->execute();
$stmt->store_result();
// If there have been more than 5 failed logins
if ($stmt->num_rows > 5) {
return true;
} else {
return false;
}
}
}
function login_check($mysqli) {
// Check if all session variables are set
if (isset($_SESSION['user_id'],
$_SESSION['email'],
$_SESSION['username'],
$_SESSION['login_string'])) {
$user_id = $_SESSION['user_id'];
$email = $_SESSION['email'];
$login_string = $_SESSION['login_string'];
$username = $_SESSION['username'];
// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];
if ($stmt = $mysqli->prepare("SELECT password
FROM members
WHERE id = ? LIMIT 1")) {
// Bind "$user_id" to parameter.
$stmt->bind_param('i', $user_id);
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
if ($stmt->num_rows == 1) {
// If the user exists get variables from result.
$stmt->bind_result($password);
$stmt->fetch();
$login_check = hash('sha512', $password . $user_browser);
if ($login_check == $login_string) {
// Logged In!!!!
return true;
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
}
function esc_url($url) {
if ('' == $url) {
return $url;
}
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);
$strip = array('%0d', '%0a', '%0D', '%0A');
$url = (string) $url;
$count = 1;
while ($count) {
$url = str_replace($strip, '', $url, $count);
}
$url = str_replace(';//', '://', $url);
$url = htmlentities($url);
$url = str_replace('&', '&', $url);
$url = str_replace("'", ''', $url);
if ($url[0] !== '/') {
// We're only interested in relative links from $_SERVER['PHP_SELF']
return '';
} else {
return $url;
}
}
答案 0 :(得分:2)
请查看password_hash()和password_verify()功能,MD5或sha512 不适合哈希密码,因为它们太快而且可以粗暴 - 太容易了。 password_hash函数会自己生成salt,你不需要在数据库中有一个额外的字段来存储它。
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
注意:使用password_hash函数,不需要使用mysql_real_escape_string转义密码,只需使用原始用户条目。
修改强>
所以我会尝试在你的代码中指出一些问题,说实话它看起来有点奇怪。我会尝试重新开始并使用PDO或mysqli而不是mysql函数,这样可以更容易防止SQL注入。
一个问题是你重复使用$ password变量,导致错误的比较,但因为你使用了==而不是=它什么都不做:
$password = mysql_real_escape_string(md5($_POST['password']));
...
$password == $rows['password'];
...
elseif ($password != $password):
$msg = "The CURRENT password you entered is incorrect.";
我自己花了很多时间来寻找描述性的变量名称,这有助于防止这样的错误。
$oldPassword = $_POST['password'];
...
$passwordHashFromDb = $rows['password'];
...
elseif (!password_verify($oldPassword, $passwordHashFromDb))
$msg = "The CURRENT password you entered is incorrect.";
然后,在将新密码存储在数据库中之前,您需要计算哈希:
$username = mysql_real_escape_string($_POST['username']);
$newPassword = $_POST['npassword'];
...
$newPasswordHash = password_hash($newPassword, PASSWORD_BCRYPT);
mysql_query("UPDATE members SET password = '$newPasswordHash' WHERE username = '$username'");
在您的注册脚本中还有其他问题,您肯定不希望用户输入128个字符的密码吗?
if (strlen($password) != 128) { // looks strange to me
您应该使用与上面相同的方法,而不是使用不同的哈希算法:
// Create salted password
$passwordHash = password_hash($password, PASSWORD_BCRYPT);
// Insert the new user into the database
if ($insert_stmt = $mysqli->prepare("INSERT INTO members (username, email, password) VALUES (?, ?, ?)")) {
$insert_stmt->bind_param('sss', $username, $email, $passwordHash);
...
在登录脚本中,检查密码是否与数据库中存储的密码匹配。
if ($db_password == $password) {
// Password is correct!
你应该像这样测试哈希:
if (password_verify($password, $db_password) {
// Password is correct!
对password_hash()函数的调用对登录脚本没有帮助,应该删除。
答案 1 :(得分:0)
修改后的代码中还有一些注释。这是你应该怎么做的。 从数据库中获取旧盐
//Gather database information
while ($rows = mysql_fetch_array($query)):
$username = $rows['username']; //single equals to assign value
$password = $rows['password'];
$user_salt = $rows['salt']; // here get old salt
endwhile;
此部分用于阅读和使用旧盐
else:
//$msg = "Your Password has been changed.";
$salted_password = hash('sha512', $npassword . $user_salt);// here use old salt
mysql_query("UPDATE members SET password = '$salted_password' WHERE username = '$username'");
endif;