我如何存储我的用户?密码安全吗?

发布于 2024-08-08 05:59:17 字数 652 浏览 8 评论 0原文

这比普通的 MD5 安全多少?我刚刚开始研究密码安全性。我对 PHP 还很陌生。

$salt = 'csdnfgksdgojnmfnb';

$password = md5($salt.$_POST['password']);
$result = mysql_query("SELECT id FROM users
                       WHERE username = '".mysql_real_escape_string($_POST['username'])."'
                       AND password = '$password'");

if (mysql_num_rows($result) < 1) {
    /* Access denied */
    echo "The username or password you entered is incorrect.";
} 
else {
    $_SESSION['id'] = mysql_result($result, 0, 'id');
    #header("Location: ./");
    echo "Hello $_SESSION[id]!";
}

How much more safe is this than plain MD5? I've just started looking into password security. I'm pretty new to PHP.

$salt = 'csdnfgksdgojnmfnb';

$password = md5($salt.$_POST['password']);
$result = mysql_query("SELECT id FROM users
                       WHERE username = '".mysql_real_escape_string($_POST['username'])."'
                       AND password = '$password'");

if (mysql_num_rows($result) < 1) {
    /* Access denied */
    echo "The username or password you entered is incorrect.";
} 
else {
    $_SESSION['id'] = mysql_result($result, 0, 'id');
    #header("Location: ./");
    echo "Hello $_SESSION[id]!";
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

风启觞 2024-08-15 05:59:17

确保密码存储方案安全的最简单方法是使用标准库

由于安全性往往比大多数程序员单独解决的要复杂得多,而且有更多看不见的搞砸的可能性,因此使用标准库几乎总是最简单和最安全(如果不是唯一)的可用选项。

新的 PHP 密码 API (5.5.0+)

如果您使用 PHP 5.5.0 或更高版本,您可以使用新的简化密码哈希 API

使用 PHP 密码 API 的代码示例:(

<?php
// $hash is what you would store in your database
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]);

// $hash would be the $hash (above) stored in your database for this user
$checked = password_verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

如果您仍在使用旧版 5.3.7 或更高版本,您可以安装 ircmaxell/password_compat 来访问内置功能)

< br>

改进加盐哈希:添加胡椒

如果您想要额外的安全性,安全人员现在(2017 年)建议添加 'pepper' 添加到(自动)加盐密码哈希值。

我建议有一个简单的直接类可以安全地实现此模式:
Netsilik/PepperedPasswords
github)。
它附带 MIT 许可证,因此您可以随心所欲地使用它,即使在专有项目中也是如此。

使用 Netsilik/PepperedPasswords 的代码示例:

<?php
use Netsilik/Lib/PepperedPasswords;

// Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper).
$config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF');

$hasher = new PepperedPasswords($config['pepper']);

// $hash is what you would store in your database
$hash = $hasher->hash($_POST['password']);

// $hash would be the $hash (above) stored in your database for this user
$checked = $hasher->verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

OLD 标准库

请注意:您应该不再需要这个了!这仅出于历史目的。

看一下:便携式 PHP 密码哈希框架phpass 并确保尽可能使用 CRYPT_BLOWFISH 算法。

使用 phpass (v0.2) 的代码示例:

<?php
require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hash (above) stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

PHPass 已在一些非常知名的项目中实现:

  • phpBB3
  • WordPress 2.5+ 以及 bbPress
  • Drupal 7 版本,(模块可用于 Drupal 5 和 6)
  • 其他

好处是你不需要担心细节,这些细节已经由有经验的人编程并审查过被互联网上的很多人所关注。

有关密码存储方案的更多信息,请阅读 Jeff 的博客文章:您可能错误地存储了密码

无论您做什么,如果您选择“我会自己做,谢谢'的方法,不要再使用MD5SHA1。它们是很好的哈希算法,但出于安全目的被认为已损坏。

目前,使用 crypt 和 CRYPT_BLOWFISH 是最佳实践。
PHP 中的 CRYPT_BLOWFISH 是 Bcrypt 哈希的实现。 Bcrypt 基于 Blowfish 分组密码,利用其昂贵的密钥设置来减慢算法速度。

The easiest way to get your password storage scheme secure is by using a standard library.

Because security tends to be a lot more complicated and with more invisible screw up possibilities than most programmers could tackle alone, using a standard library is almost always easiest and most secure (if not the only) available option.

The new PHP password API (5.5.0+)

If you are using PHP version 5.5.0 or newer, you can use the new simplified password hashing API

Example of code using PHP's password API:

<?php
// $hash is what you would store in your database
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]);

// $hash would be the $hash (above) stored in your database for this user
$checked = password_verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

(In case you are still using legacy 5.3.7 or newer you can install ircmaxell/password_compat to have access to the build-in functions)

Improving upon salted hashes: add pepper

If you want extra security, the security folks now (2017) recommend adding a 'pepper' to the (automatically) salted password hashes.

There is a simple, drop in class that securely implements this pattern, I recommend:
Netsilik/PepperedPasswords
(github).
It comes with a MIT License, so you can use it however you want, even in proprietary projects.

Example of code using Netsilik/PepperedPasswords:

<?php
use Netsilik/Lib/PepperedPasswords;

// Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper).
$config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF');

$hasher = new PepperedPasswords($config['pepper']);

// $hash is what you would store in your database
$hash = $hasher->hash($_POST['password']);

// $hash would be the $hash (above) stored in your database for this user
$checked = $hasher->verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

The OLD standard library

Please note: you should not be needing this anymore! This is only here for historical purposes.

Take a look at: Portable PHP password hashing framework: phpass and make sure you use the CRYPT_BLOWFISH algorithm if at all possible.

Example of code using phpass (v0.2):

<?php
require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hash (above) stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

PHPass has been implemented in some quite well known projects:

  • phpBB3
  • WordPress 2.5+ as well as bbPress
  • the Drupal 7 release, (module available for Drupal 5 & 6)
  • others

The good thing is that you do not need to worry about the details, those details have been programmed by people with experience and reviewed by many folks on the internet.

For more information on password storage schemes, read Jeff`s blog post: You're Probably Storing Passwords Incorrectly

Whatever you do if you go for the 'I'll do it myself, thank you' approach, do not use MD5 or SHA1 anymore. They are nice hashing algorithm, but considered broken for security purposes.

Currently, using crypt, with CRYPT_BLOWFISH is the best practice.
CRYPT_BLOWFISH in PHP is an implementation of the Bcrypt hash. Bcrypt is based on the Blowfish block cipher, making use of it's expensive key setup to slow the algorithm down.

倒数 2024-08-15 05:59:17

如果您使用参数化查询而不是连接 SQL 语句,您的用户将会更加安全。并且对于每个用户来说应该是唯一的,并且应该与密码一起存储哈希。

Your users will be much safer if you used parameterized queries instead of concatenating SQL statements. And the salt should be unique for each user and should be stored along with the password hash.

给不了的爱 2024-08-15 05:59:17

更好的方法是让每个用户都有一个独特的盐。

使用 salt 的好处是,它使攻击者更难预先生成每个字典单词的 MD5 签名。但是,如果攻击者得知您有固定盐,他们就可以预先生成以您的固定盐为前缀的每个字典单词的 MD5 签名。

更好的方法是每次用户更改密码时,您的系统都会生成随机盐并将该盐与用户记录一起存储。它使得检查密码的成本更高一些(因为您需要在生成 MD5 签名之前查找盐),但它使攻击者更难预先生成 MD5。

A better way would be for each user to have a unique salt.

The benefit of having a salt is that it makes it harder for an attacker to pre-generate the MD5 signature of every dictionary word. But if an attacker learns that you have a fixed salt, they could then pre-generate the MD5 signature of every dictionary word prefixed by your fixed salt.

A better way is each time a user changes their password, your system generate a random salt and store that salt along with the user record. It makes it a bit more expensive to check the password (since you need to look up the salt before you can generate the MD5 signature) but it makes it much more difficult for an attacker to pre-generate MD5's.

爱给你人给你 2024-08-15 05:59:17

随着 PHP 5.5(我所描述的甚至可以用于更早的版本,见下文)即将到来,我建议使用其新的内置解决方案: password_hash()password_verify()。它提供了几个选项,以达到您需要的密码安全级别(例如通过 $options 数组指定“cost”参数)

<?php
var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT));

$options = array(
    'cost' => 7, // this is the number of rounds for bcrypt
    // 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended
);
var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options));
?>

将返回

string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."

正如您可能看到的,该字符串包含 salt以及选项中指定的成本。它还包含所使用的算法。

因此,在检查密码时(例如,当用户登录时),当使用免费的 password_verify() 函数时,它将从密码哈希本身中提取必要的加密参数。

如果不指定盐,则每次调用 password_hash() 时生成的密码哈希值都会不同,因为盐是随机生成的。因此,即使密码正确,将先前的哈希值与新生成的哈希值进行比较也会失败。

验证的工作原理如下:

var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));

var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));

我希望提供这些内置函数很快就能在数据被盗的情况下提供更好的密码安全性,因为它减少了程序员在正确实现时需要投入的精力。

有一个小型库(一个 PHP 文件)可以为您提供 PHP 5.3.7+ 中 PHP 5.5 的 password_hashhttps://github.com/ircmaxell/password_compat

With PHP 5.5 (what I describe is available to even earlier versions, see below) around the corner I'd like to suggest to use its new, built-in solution: password_hash() and password_verify(). It provides several options in order to achieve the level of password security you need (for example by specifying a "cost" parameter through the $options array)

<?php
var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT));

$options = array(
    'cost' => 7, // this is the number of rounds for bcrypt
    // 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended
);
var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options));
?>

will return

string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."

As you might see, the string contains the salt as well as the cost that was specified in the options. It also contains the algorithm used.

Therefore, when checking the password (for example when the user logs in), when using the complimentary password_verify() function it will extract the necessary crypto parameters from the password hash itself.

When not specifying a salt, the generated password hash will be different upon every call of password_hash() because the salt is generated randomly. Therefore comparing a previous hash with a newly generated one will fail, even for a correct password.

Verifying works like this:

var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));

var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));

I hope that providing these built-in functions will soon provide better password security in case of data theft, as it reduces the amount of thought the programmer has to put into a proper implementation.

There is a small library (one PHP file) that will give you PHP 5.5's password_hash in PHP 5.3.7+: https://github.com/ircmaxell/password_compat

夜吻♂芭芘 2024-08-15 05:59:17

这对我来说没问题。 Atwood 先生写了MD5 对抗彩虹表的优势,基本上是长盐就像你坐得很漂亮(尽管有一些随机的标点符号/数字,它可以改善它)。

您还可以查看 SHA-1,它最近似乎越来越流行。

That's fine with me. Mr Atwood wrote about the strength of MD5 against rainbow tables, and basically with a long salt like that you're sitting pretty (though some random punctuation/numbers, it could improve it).

You could also look at SHA-1, which seems to be getting more popular these days.

奈何桥上唱咆哮 2024-08-15 05:59:17

我想补充一下:

  • 不要按长度限制用户密码

为了与旧系统兼容,通常会对密码的最大长度设置限制。这是一个糟糕的安全策略:如果您设置限制,请仅将其设置为密码的最小长度。

  • 不要通过电子邮件发送用户密码

为了恢复忘记的密码,您应该发送用户可以更改密码的地址。

  • 更新用户密码的哈希值

密码哈希值可能已过时(算法的参数可能已更新)。通过使用函数 password_needs_rehash() 你可以检查一下。

I want to add:

  • Don't limit users passwords by length

For compatibility with old systems often set a limit for the maximum length of the password. This is a bad security policy: if you set restriction, set it only for the minimum length of passwords.

  • Don't send user passwords via email

For recovering a forgotten password you should send the address by which user can change the password.

  • Update the hashes of users passwords

The password hash may be out of date (parameters of the algorithm may be updated). By using the function password_needs_rehash() you can check it out.

慵挽 2024-08-15 05:59:17
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文