此PHP注册码中是否存在任何安全漏洞?

时间:2022-05-14 05:01:44

Can you experts give me some thougths on this code? Some security hole i have missed? Can you see any potential threats? Something i can do better?

你可以请专家给我一些关于这段代码的信息吗?我错过了一些安全漏洞?你能看到任何潜在的威胁吗?我可以做得更好吗?

I'm still learning :) Thanks

我还在学习:)谢谢

<?php

if (isset($_POST['username'])) {

$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
$password2 = mysql_real_escape_string($_POST['password2']);
$encrypted_password = md5($password);


// remove eventuakl space
foreach($_POST as $key => $val) $_POST[$key] = trim($val);


// check if username is taken
$query = mysql_query("SELECT COUNT(*) FROM users WHERE username = '$username'");
if (mysql_result($query, 0) > 0) {
$reg_error[] = 0;
}

// make sure username only cosist of at least 3 letters, numbers or _ -
if (!preg_match('/^[a-zA-Z0-9_-]{3,}$/', $username)) {
$reg_error[] = 4;  
}


// check for empty fields
if (empty($username) || empty($password) || empty($password2)) {
$reg_error[] = 2;
}

// check if the passwords match
if ($password != $password2) {
$reg_error[] = 3;
}

// save if error is unset
if (!isset($reg_error)) {
mysql_query("INSERT INTO users (username, password, registered, registration_ip)
             VALUES('$username', '$encrypted_password', '".time()."', '".$_SERVER['SERVER_ADDR']."')");

$_SESSION['id'] = mysql_insert_id();
header('refresh: 3; url=/home');

}


}
?>

Login.php

if (isset($_POST['username'])) {

$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
$md5_password = md5($password); 

$query = mysql_query("SELECT id FROM users WHERE username = '$username' and password = '$md5_password'");


if (mysql_num_rows($query) == 0) {
header("Location: ".$_SERVER['REQUEST_URI']."");
exit;
}

// set session
$_SESSION['id'] = mysql_result($query, 0, 'id');
header("Location: /");
exit;

6 个解决方案

#1


You didn't salt the password.

你没有密码。

Also, md5() is considered not strong enough for hashing passwords.

此外,md5()被认为不足以进行散列密码。

Use hash('sha256', $password) instead.

请改用hash('sha256',$ password)。

#2


I assume you're serving this on https, though you don't mention whether you do -- if you're not, username and password travel on the open net in the clear, and that's definitely not very safe.

我假设你在https上提供这个服务,虽然你没有提到你是否这样做 - 如果你不这样做,用户名和密码在明确的网络上旅行,这绝对不是很安全。

There's a race condition -- you check whether the username is taken, first, and only later do you insert it. You should use a transaction, a least, and ideally just try to insert (with the uniqueness constraint imposed by the database) and catch the error in case of duplicates. And, you should do this only after all other sanity checks, i.e. when you've convinced yourself that, apart from possible duplicates, the registration attempt is OK.

有竞争条件 - 您首先检查用户名是否被占用,然后才会插入。您应该至少使用一个事务,理想情况下只是尝试插入(使用数据库强加的唯一性约束)并在重复的情况下捕获错误。并且,您应该在所有其他健全性检查之后执行此操作,即,当您确信自己除了可能的重复之外,注册尝试是可以的。

#3


Little bobby tables will give you a lot of headaches since you do not check for username validity.

由于您没有检查用户名有效性,因此小小的桌子会给您带来很多麻烦。

#4


You need to salt the password.

你需要加密密码。

This is placed in the wrong place. Move it up a few lines before the $_POST vars are used.

这是放在错误的地方。在使用$ _POST变量之前将其向上移动几行。

// remove eventuakl space
foreach($_POST as $key => $val) $_POST[$key] = trim($val);

You are escaping the password fields for no reason. They are not being sent to the database. md5($password) is going to the database and it is not escaped.

您无缘无故地转义密码字段。它们不会被发送到数据库。 md5($ password)将进入数据库并且不会被转义。

EDIT: On the login side, you should be trimming anything you are trim on the registrations side.

编辑:在登录方面,您应该修改注册方面的任何内容。

#5


Your error checking is out of order. I'd do the error checking in this order:

您的错误检查无序。我按此顺序进行错误检查:

  1. Check for empty fields
  2. 检查空字段

  3. Check that the fields have valid values (filtering input)
  4. 检查字段是否有有效值(过滤输入)

  5. Escape the fields with mysql_real_escape_string before using the fields in SQL
  6. 在使用SQL中的字段之前,使用mysql_real_escape_string转义字段

  7. Check for the user in the SQL table
  8. 检查SQL表中的用户

If you find an error don't continue with further checks. Guard each error check similar to your guard on the final INSERT statement.

如果发现错误,请不要继续进一步检查。在最后的INSERT语句中保护每个错误检查,类似于您的保护。

You have no edits on the password fields besides using mysql_real_escape_string?

除了使用mysql_real_escape_string之外,您没有对密码字段进行编辑?

You should do mysql_connect before using mysql_real_escape_string. mysql_real_escape_string will use the connection to determine the character set of the connection. The character set will identify which characters to escape.

你应该在使用mysql_real_escape_string之前做mysql_connect。 mysql_real_escape_string将使用该连接来确定连接的字符集。字符集将标识要转义的字符。

#6


You should use parameters instead of building your sql dynamically. It will help prevent sql injection attacks. Little bobby tables will get you.

您应该使用参数而不是动态构建您的SQL。它将有助于防止SQL注入攻击。小小的桌子可以帮到你。

#1


You didn't salt the password.

你没有密码。

Also, md5() is considered not strong enough for hashing passwords.

此外,md5()被认为不足以进行散列密码。

Use hash('sha256', $password) instead.

请改用hash('sha256',$ password)。

#2


I assume you're serving this on https, though you don't mention whether you do -- if you're not, username and password travel on the open net in the clear, and that's definitely not very safe.

我假设你在https上提供这个服务,虽然你没有提到你是否这样做 - 如果你不这样做,用户名和密码在明确的网络上旅行,这绝对不是很安全。

There's a race condition -- you check whether the username is taken, first, and only later do you insert it. You should use a transaction, a least, and ideally just try to insert (with the uniqueness constraint imposed by the database) and catch the error in case of duplicates. And, you should do this only after all other sanity checks, i.e. when you've convinced yourself that, apart from possible duplicates, the registration attempt is OK.

有竞争条件 - 您首先检查用户名是否被占用,然后才会插入。您应该至少使用一个事务,理想情况下只是尝试插入(使用数据库强加的唯一性约束)并在重复的情况下捕获错误。并且,您应该在所有其他健全性检查之后执行此操作,即,当您确信自己除了可能的重复之外,注册尝试是可以的。

#3


Little bobby tables will give you a lot of headaches since you do not check for username validity.

由于您没有检查用户名有效性,因此小小的桌子会给您带来很多麻烦。

#4


You need to salt the password.

你需要加密密码。

This is placed in the wrong place. Move it up a few lines before the $_POST vars are used.

这是放在错误的地方。在使用$ _POST变量之前将其向上移动几行。

// remove eventuakl space
foreach($_POST as $key => $val) $_POST[$key] = trim($val);

You are escaping the password fields for no reason. They are not being sent to the database. md5($password) is going to the database and it is not escaped.

您无缘无故地转义密码字段。它们不会被发送到数据库。 md5($ password)将进入数据库并且不会被转义。

EDIT: On the login side, you should be trimming anything you are trim on the registrations side.

编辑:在登录方面,您应该修改注册方面的任何内容。

#5


Your error checking is out of order. I'd do the error checking in this order:

您的错误检查无序。我按此顺序进行错误检查:

  1. Check for empty fields
  2. 检查空字段

  3. Check that the fields have valid values (filtering input)
  4. 检查字段是否有有效值(过滤输入)

  5. Escape the fields with mysql_real_escape_string before using the fields in SQL
  6. 在使用SQL中的字段之前,使用mysql_real_escape_string转义字段

  7. Check for the user in the SQL table
  8. 检查SQL表中的用户

If you find an error don't continue with further checks. Guard each error check similar to your guard on the final INSERT statement.

如果发现错误,请不要继续进一步检查。在最后的INSERT语句中保护每个错误检查,类似于您的保护。

You have no edits on the password fields besides using mysql_real_escape_string?

除了使用mysql_real_escape_string之外,您没有对密码字段进行编辑?

You should do mysql_connect before using mysql_real_escape_string. mysql_real_escape_string will use the connection to determine the character set of the connection. The character set will identify which characters to escape.

你应该在使用mysql_real_escape_string之前做mysql_connect。 mysql_real_escape_string将使用该连接来确定连接的字符集。字符集将标识要转义的字符。

#6


You should use parameters instead of building your sql dynamically. It will help prevent sql injection attacks. Little bobby tables will get you.

您应该使用参数而不是动态构建您的SQL。它将有助于防止SQL注入攻击。小小的桌子可以帮到你。