提问人:luiscubal 提问时间:12/31/2008 最后编辑:General Grievanceluiscubal 更新时间:9/4/2023 访问量:258850
PHP 密码的安全哈希和盐
Secure hash and salt for PHP passwords
问:
目前据说MD5是部分不安全的。考虑到这一点,我想知道使用哪种机制来保护密码。
这个问题,“双重哈希”密码是否不如仅哈希一次安全?建议多次哈希可能是一个好主意,而如何为单个文件实现密码保护?建议使用盐。
我正在使用 PHP。我想要一个安全快速的密码加密系统。对密码进行一百万次哈希处理可能更安全,但也更慢。如何在速度与安全之间取得良好的平衡?此外,我希望结果具有恒定数量的字符。
- 哈希机制必须在 PHP 中可用
- 它必须是安全的
- 它可以使用盐(在这种情况下,所有的盐都一样好吗?有什么方法可以产生好的盐吗?
另外,我是否应该在数据库中存储两个字段(例如,一个使用 MD5,另一个使用 SHA)?它会让它更安全还是更安全?
如果我不够清楚,我想知道使用哪些哈希函数以及如何选择一个好的盐,以便有一个安全快速的密码保护机制。
不能完全涵盖我的问题的相关问题:
PHP
中的SHA和MD5有什么区别 简单密码加密
存储密钥、密码的安全方法 asp.net
如何在 Tomcat 5.5 中实现加盐密码
答:
免责声明:这个答案写于2008年。
从那时起,PHP为我们提供了
password_hash
和password_verify
,并且自推出以来,它们一直是推荐的密码散列和检查方法。不过,答案的理论仍然是一本好书。
TL;博士
注意 事项
- 不要限制用户可以为密码输入的字符。只有白痴才会这样做。
- 不要限制密码的长度。如果您的用户想要一个带有 supercalifragilisticexpialidocious 的句子,请不要阻止他们使用它。
- 不要删除或转义密码中的 HTML 和特殊字符。
- 切勿以纯文本形式存储用户的密码。
- 切勿通过电子邮件将密码发送给您的用户,除非他们丢失了密码,并且您发送了临时密码。
- 永远不要以任何方式记录密码。
- 永远不要使用 SHA1 或 MD5 甚至 SHA256 散列密码!现代破解程序可以分别超过 6000 亿和 1800 亿个哈希/秒。
- 不要将 bcrypt 和 hash() 的原始输出混合在一起,要么使用十六进制输出,要么base64_encode它。(这适用于任何可能包含恶意程序的输入,这可能会严重削弱安全性。
\0
婴儿 床
- 尽可能使用 scrypt;bcrypt 如果不能。
- 如果不能将 bcrypt 或 scrypt 与 SHA2 哈希一起使用,请使用 PBKDF2。
- 当数据库遭到入侵时,重置每个人的密码。
- 实现合理的 8-10 个字符的最小长度,并要求至少 1 个大写字母、1 个小写字母、一个数字和一个符号。这将提高密码的熵,从而使其更难破解。(请参阅“什么是好的密码?”部分进行一些辩论。
为什么要散列密码?
哈希密码背后的目标很简单:通过破坏数据库来防止对用户帐户的恶意访问。因此,密码散列的目标是通过花费黑客或破解者太多的时间或金钱来计算纯文本密码来阻止他们。时间/成本是你武器库中最好的威慑力量。
您希望在用户帐户上获得良好、可靠的哈希值的另一个原因是让您有足够的时间来更改系统中的所有密码。如果您的数据库遭到入侵,您将需要足够的时间来至少锁定系统,如果不更改数据库中的每个密码。
Whitehat Security 的首席技术官 Jeremiah Grossman 在最近的密码恢复需要暴力破解他的密码保护后在 White Hat Security 博客上表示:
有趣的是,在经历这场噩梦的过程中,我学到了很多我不知道的关于密码破解、存储和复杂性的知识。我开始理解为什么密码存储比密码复杂性重要得多。如果您不知道密码是如何存储的,那么您真正可以依赖的就是复杂性。这可能是密码和加密专业人士的常识,但对于普通的信息安全或网络安全专家来说,我对此表示高度怀疑。
(强调我的。
到底什么是好的密码?
熵。(并不是说我完全同意兰德尔的观点。
简而言之,熵是密码内的变化程度。当密码仅为小写罗马字母时,只有 26 个字符。这并没有太大的变化。字母数字密码更好,有 36 个字符。但是允许大写和小写,加上符号,大约是 96 个字符。这比单纯的信件要好得多。一个问题是,为了让我们的密码令人难忘,我们插入了模式,从而减少了熵。哎呀!
密码熵很容易近似。使用全范围的 ascii 字符(大约 96 个可键入字符)会产生每个字符 6.6 个熵,对于密码来说,8 个字符仍然太低(52.679 位熵)对于未来的安全性。但好消息是:较长的密码和带有 unicode 字符的密码确实会增加密码的熵并使其更难破解。
在Crypto StackExchange网站上有关于密码熵的更长的讨论。一个好的谷歌搜索也会出现很多结果。
在我与@popnoodles交谈的评论中,他指出,强制执行X长度的密码策略,其中包含X个字母,数字,符号等,实际上可以通过使密码方案更具可预测性来减少熵。我同意。Randomess,尽可能真正随机,始终是最安全但最不令人难忘的解决方案。
据我所知,制作世界上最好的密码是 Catch-22。要么它不令人难忘,要么太可预测,要么太短,要么太多的 unicode 字符(很难在 Windows/移动设备上输入),要么太长,等等。对于我们的目的来说,没有一个密码是真正好的,所以我们必须保护它们,就好像它们在诺克斯堡一样。
最佳做法
Bcrypt 和 scrypt 是当前的最佳实践。Scrypt 会比 bcrypt 更好,但它还没有被 Linux/Unix 或 Web 服务器采用为标准,并且还没有发布对其算法的深入评论。但是,该算法的未来看起来确实很有希望。如果你正在使用 Ruby,有一个 scrypt gem 可以帮助你,Node.js 现在有自己的 scrypt 包。您可以在 PHP 中通过 Scrypt 扩展或 Libsodium 扩展(两者在 PECL 中都可用)使用 Scrypt。
如果您想了解如何使用 bcrypt,或者找到一个好的包装器或使用 PHPASS 之类的东西来实现更遗留的实现,我强烈建议您阅读 crypt 函数的文档。我建议至少 12 轮 bcrypt,如果不是 15 到 18 轮的话。
当我得知 bcrypt 只使用 blowfish 的密钥计划时,我改变了使用 bcrypt 的想法,并具有可变成本机制。后者允许您通过增加河豚已经昂贵的密钥计划来增加暴力破解密码的成本。
平均做法
我几乎无法想象这种情况了。PHPASS 支持 PHP 3.0.18 到 5.3,因此它几乎可以用于所有可以想象的安装,如果您不确定您的环境是否支持 bcrypt,则应使用它。
但是假设您根本无法使用 bcrypt 或 PHPASS。然后呢?
尝试使用环境/应用程序/用户感知可以容忍的最大轮数实现 PDKBF2。我推荐的最低数量是 2500 发。此外,请确保使用 hash_hmac() ()(如果可用),以使操作更难重现。
未来实践
PHP 5.5 中即将推出的是一个完整的密码保护库,它消除了使用 bcrypt 的任何痛苦。虽然我们大多数人在大多数常见环境中都停留在 PHP 5.2 和 5.3 上,尤其是共享主机,但 @ircmaxell 已经为即将到来的 API 构建了一个向后兼容 PHP 5.3.7 的兼容层。
密码学回顾和免责声明
实际破解哈希密码所需的计算能力并不存在。计算机“破解”密码的唯一方法是重新创建密码并模拟用于保护密码的哈希算法。哈希的速度与其暴力破解能力呈线性关系。更糟糕的是,大多数哈希算法可以很容易地并行化,以更快地执行。这就是为什么像 bcrypt 和 scrypt 这样昂贵的方案如此重要的原因。
您不可能预见到所有威胁或攻击途径,因此您必须尽最大努力预先保护您的用户。如果你不这样做,那么你甚至可能会错过你被攻击的事实,直到为时已晚......你要承担责任。为了避免这种情况,首先要表现得偏执。攻击您自己的软件(内部)并试图窃取用户凭据,或修改其他用户的帐户或访问他们的数据。如果你不测试系统的安全性,那么你不能责怪任何人,只能责怪你自己。
最后:我不是密码学家。无论我说什么都是我的观点,但我碰巧认为这是基于良好的常识......和大量的阅读。记住,尽可能偏执,让事情尽可能难以入侵,然后,如果你仍然担心,请联系白帽黑客或密码学家,看看他们对你的代码/系统的评价。
评论
我不会以两种不同的方式存储散列的密码,因为这样系统至少与使用中最弱的散列算法一样弱。
我通常将 SHA1 和 salt 与用户 ID(或其他一些特定于用户的信息)一起使用,有时我还会使用常量盐(所以我有 2 个部分的盐)。
SHA1 现在也被认为在某种程度上受到了损害,但程度远低于 MD5。通过使用盐(任何盐),您可以防止使用通用彩虹表来攻击您的哈希值(有些人甚至通过搜索哈希值成功地将 Google 用作彩虹表)。可以想象,攻击者可能会使用你的盐生成一个彩虹表,所以这就是为什么你应该包括一个用户特定的盐。这样,他们就必须为系统中的每条记录生成一个彩虹表,而不仅仅是为整个系统生成一个彩虹表!通过这种腌制方式,即使是 MD5 也相当安全。
评论
谷歌表示 SHA256 可用于 PHP。
你绝对应该使用盐。我建议使用随机字节(不要将自己局限于字符和数字)。像往常一样,您选择的时间越长,它就越安全,速度越慢。我猜 64 字节应该没问题。
评论
在可预见的未来,SHA1 和盐应该就足够了(当然,这取决于你是为 Fort Knox 编码还是为你的购物清单编写登录系统)。如果 SHA1 对您来说不够好,请使用 SHA256。
可以这么说,盐的想法是使散列结果失去平衡。例如,已知空字符串的 MD5 哈希值为 。因此,如果内存足够好的人会看到该哈希值,并知道它是空字符串的哈希值。但是,如果字符串被加盐(例如,使用字符串“”),则“空字符串”(即“”)的哈希值将变为 ,因此回溯不明显。我想说的是,使用任何盐都比不使用要好。因此,知道使用哪种盐并不太重要。d41d8cd98f00b204e9800998ecf8427e
MY_PERSONAL_SALT
MY_PERSONAL_SALT
aeac2612626724592271634fb14d3ea6
实际上有些网站就是这样做的——你可以给它一个 (md5) 哈希值,它会吐出一个已知的明文来生成该特定的哈希值。如果您要访问存储普通 md5 哈希值的数据库,那么输入管理员对此类服务的哈希值并登录将是微不足道的。但是,如果密码被加盐,这样的服务将变得无效。
此外,双重散列通常被认为是不好的方法,因为它会减少结果空间。所有流行的哈希值都是固定长度的。因此,您只能拥有此固定长度的有限值,并且结果的可变性较小。这可以被视为另一种形式的腌制,但我不推荐它。
评论
sha1(sha1($foo))
$hash = sha1(sha1($salt . $password) . $salt)
最后,从数学上讲,双重散列没有任何好处。然而,在实践中,它对于防止基于彩虹表的攻击很有用。换句话说,它并不比使用盐进行哈希处理更有好处,后者在应用程序或服务器上花费的处理器时间要少得多。
评论
虽然这个问题已经得到回答,但我只想重申,用于散列的盐应该是随机的,而不是像第一个答案中建议的那样使用电子邮件地址。
更多解释可在(archive.org的副本)http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/
最近,我讨论了用随机位加盐的密码哈希是否比用可猜测或已知的盐加盐的密码哈希更安全。我看看:
如果存储密码的系统以及存储随机盐的系统被泄露,攻击者将可以访问哈希和盐,因此盐是否是随机的并不重要。攻击者可以生成预先计算的彩虹表来破解哈希值。有趣的部分来了 - 生成预先计算的表并不是那么简单。让我们以 WPA 安全模型为例。您的 WPA 密码实际上永远不会发送到无线接入点。取而代之的是,它使用您的 SSID(网络名称 - 如 Linksys、Dlink 等)进行哈希处理。关于其工作原理的一个很好的解释在这里。为了从哈希中检索密码,您需要知道密码以及盐(网络名称)。Church of Wifi 已经预先计算了哈希表,其中包含前 1000 个 SSID 和大约 100 万个密码。所有表的大小约为 40 GB。正如您在他们的网站上所读到的,有人使用了 15 个 FGPA 数组 3 天来生成这些表。
假设受害者使用SSID为“a387csf3”,密码为“123456”,会被这些表破解吗?不!。。它不能。即使密码较弱,这些表也没有 SSID a387csf3 的哈希值。这就是随机盐的美妙之处。它将阻止那些在预先计算的桌子上茁壮成长的饼干。它能阻止一个坚定的黑客吗?可能不是。但是使用随机盐确实提供了额外的防御层。
当我们讨论这个话题时,让我们讨论一下将随机盐存储在单独系统上的额外优势。
场景 #1:密码哈希存储在系统 X 上,用于哈希的盐值存储在系统 Y 上。这些盐值是可猜测的或已知的(例如用户名)
场景#2:密码哈希存储在系统X上,用于哈希的盐值存储在系统Y上。这些盐值是随机的。
正如您可以猜到的那样,如果系统 X 遭到破坏,那么在单独的系统上使用随机盐具有巨大的优势(场景 #2)。攻击者需要猜测加法值才能破解哈希值。如果使用 32 位盐,则猜测的每个密码可能需要 2^32= 4,294,967,296(约 42 亿次)迭代。
评论
一个更简单、更安全的答案 - 根本不用编写自己的密码机制,使用久经考验的机制:
对于 PHP 8(2023 年),请使用 password_hash() - 自 PHP 5.5 以来质量良好,是 PHP 核心的一部分。
大多数程序员只是不具备在不引入漏洞的情况下安全地编写加密相关代码的专业知识。
快速自检
什么是密码扩展,应使用多少次迭代?
如果您不知道答案,您应该使用 ,因为密码扩展现在是密码机制的一个关键功能,因为 CPU 的速度要快得多,并且使用 GPU 和 FPGA 以每秒数十亿次猜测的速度破解密码(使用 GPU)。password_hash()
示例:破解 Windows 密码
截至 2023 年,您可以使用 8 个 GPU 在 48 分钟内破解所有 8 个字符的 Windows 密码。(NTLM 密码使用 2880 亿个哈希值/秒)hashcat
这是暴力破解,即枚举和检查每个 8 个字符的 Windows 密码,包括特殊字符 - 而不是字典攻击。
2023 年的示例比 2012 年快约 7.5 倍,当时您可以使用 25 个 GPU 在 6 小时内破解所有 8 个字符的 Windows 密码。
现在,您还可以以合理的价格在云中租用 GPU 几个小时。
为什么 Windows 密码如此容易破解?
所有这一切都是因为 Windows 仍然不会加盐或扩展其密码,即使在 Windows 10 或 11 中也是如此,因为它需要允许 NTLMv1 登录。
这在 2023 年仍然如此——请参阅此问答。
不要犯和Microsoft一样的错误!
另请参阅
- 很好的答案,更多关于为什么或最好的方法。
password_hash()
phpass
- 这篇很好的博文为包括 bcrypt、scrypt 和 PBKDF2 在内的主要算法提供了推荐的“工作因子”(迭代次数)。
旧版 PHP
对于非常旧的 PHP (4.x):OpenWall 的 phpass 库比大多数自定义代码要好得多 - 用于 WordPress、Drupal 等。
评论
我正在使用 Phpass,这是一个简单的单文件 PHP 类,几乎可以在每个 PHP 项目中轻松实现。另见 The H.
默认情况下,它使用在 Phpass 中实现的最强可用加密,该加密是并回退到其他加密到 MD5,以提供对 Wordpress 等框架的向后兼容性。bcrypt
返回的哈希值可以按原样存储在数据库中。用于生成哈希的示例用途为:
$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);
要验证密码,可以使用:
$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);
我只想指出,PHP 5.5 包含一个密码哈希 API,它提供了一个包装器。此 API 大大简化了对密码哈希进行哈希处理、验证和重新哈希处理的任务。作者还发布了一个兼容包(以单个密码.php文件的形式,您只需使用),供使用PHP 5.3.7及更高版本并希望立即使用它的用户使用。crypt()
require
它目前仅支持 BCRYPT,但它旨在轻松扩展以包含其他密码哈希技术,并且由于该技术和成本存储为哈希的一部分,因此对您首选的哈希技术/成本的更改不会使当前哈希失效,框架将自动,在验证时使用正确的技术/成本。如果您没有明确定义自己的盐,它还会处理生成“安全”盐。
该 API 公开了四个函数:
password_get_info()
- 返回有关给定哈希值的信息password_hash()
- 创建密码哈希password_needs_rehash()
- 检查给定的哈希值是否与给定的选项匹配。用于检查哈希值是否符合您当前的技术/成本方案,允许您在必要时重新哈希值password_verify()
- 验证密码是否与哈希值匹配
目前,这些函数接受 PASSWORD_BCRYPT 和 PASSWORD_DEFAULT 密码常量,这是目前同义词,不同之处在于PASSWORD_DEFAULT“当支持更新、更强大的哈希算法时,可能会在较新的 PHP 版本中发生变化”。在登录时使用 PASSWORD_DEFAULT 和 password_needs_rehash()(并在必要时重新散列)应确保您的哈希对暴力攻击具有合理的弹性,而对您几乎没有任何作用。
编辑:我刚刚意识到这在Robert K的回答中被简要提及。我将把这个答案留在这里,因为我认为它提供了更多关于它如何工作的信息,以及它为那些不了解安全性的人提供的易用性。
我在这里找到了关于这个问题的完美主题:https://crackstation.net/hashing-security.htm,我希望你能从中受益,这里是源代码,也提供了对基于时间的攻击的预防。
<?php
/*
* Password hashing with PBKDF2.
* Author: havoc AT defuse.ca
* www: https://defuse.ca/php-pbkdf2.htm
*/
// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTES", 24);
define("PBKDF2_HASH_BYTES", 24);
define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);
function create_hash($password)
{
// format: algorithm:iterations:salt:hash
$salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" . $salt . ":" .
base64_encode(pbkdf2(
PBKDF2_HASH_ALGORITHM,
$password,
$salt,
PBKDF2_ITERATIONS,
PBKDF2_HASH_BYTES,
true
));
}
function validate_password($password, $good_hash)
{
$params = explode(":", $good_hash);
if(count($params) < HASH_SECTIONS)
return false;
$pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
return slow_equals(
$pbkdf2,
pbkdf2(
$params[HASH_ALGORITHM_INDEX],
$password,
$params[HASH_SALT_INDEX],
(int)$params[HASH_ITERATION_INDEX],
strlen($pbkdf2),
true
)
);
}
// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
$diff = strlen($a) ^ strlen($b);
for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
{
$diff |= ord($a[$i]) ^ ord($b[$i]);
}
return $diff === 0;
}
/*
* PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
* $algorithm - The hash algorithm to use. Recommended: SHA256
* $password - The password.
* $salt - A salt that is unique to the password.
* $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
* $key_length - The length of the derived key in bytes.
* $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
* Returns: A $key_length-byte key derived from the password and salt.
*
* Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
*
* This implementation of PBKDF2 was originally created by https://defuse.ca
* With improvements by http://www.variations-of-shadow.com
*/
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
die('PBKDF2 ERROR: Invalid hash algorithm.');
if($count <= 0 || $key_length <= 0)
die('PBKDF2 ERROR: Invalid parameters.');
$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);
$output = "";
for($i = 1; $i <= $block_count; $i++) {
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
if($raw_output)
return substr($output, 0, $key_length);
else
return bin2hex(substr($output, 0, $key_length));
}
?>
评论
要记住的事情
关于PHP的密码加密已经说了很多,其中大部分都是非常好的建议,但是在开始使用PHP进行密码加密之前,请确保您已经实现或准备实施以下内容。
服务器
港口
无论你的加密有多好,如果你没有正确地保护运行PHP和DB的服务器,你所有的努力都是毫无价值的。大多数服务器的运行方式相对相同,它们分配了端口,允许您通过 ftp 或 shell 远程访问它们。请确保更改您处于活动状态的远程连接的默认端口。如果不这样做,实际上已经使攻击者在访问您的系统时少了一个步骤。
用户名
对于世界上所有美好的事物,请不要使用用户名 admin、root 或类似的东西。此外,如果您在基于 unix 的系统上,请不要使 root 帐户登录可访问,它应该始终是 sudo only。
密码
你告诉你的用户要设置好的密码以避免被黑客入侵,也要这样做。当你把后门打开时,费尽心思锁上前门有什么意义呢?
数据库
服务器
理想情况下,您希望数据库和应用程序位于不同的服务器上。由于成本原因,这并不总是可行的,但它确实允许一些安全性,因为攻击者必须通过两个步骤才能完全访问系统。
用户
始终让应用程序拥有自己的帐户来访问数据库,并且仅授予其所需的权限。
然后为您准备一个单独的用户帐户,该帐户不会存储在服务器上的任何位置,甚至不会存储在应用程序中。
像往常一样,不要制作这个根或类似的东西。
密码
遵循与所有良好密码相同的准则。此外,不要在同一系统上的任何 SERVER 或 DB 帐户上重复使用相同的密码。
PHP的
密码
永远不要在数据库中存储密码,而是存储哈希和唯一盐,我稍后会解释原因。
散列法
单向哈希!!!!!!,永远不要以可以反转的方式对密码进行哈希处理,哈希应该是单向的,这意味着您不会反转它们并将它们与密码进行比较,而是以相同的方式对输入的密码进行哈希处理并比较两个哈希值。这意味着,即使攻击者可以访问数据库,他也不知道实际密码是什么,只知道其生成的哈希值。这意味着在最坏的情况下,您的用户可以更安全。
市面上有很多好的哈希函数(、等),但你需要选择一个好的算法才能使哈希有效。(bcrypt 和类似的算法是不错的算法。password_hash
hash
当哈希速度是关键时,越慢越能抵抗暴力攻击。
哈希中最常见的错误之一是哈希不是用户独有的。这主要是因为盐不是唯一产生的。
腌制
在对密码进行哈希处理之前,应始终对密码进行加盐处理。加盐会在密码中添加一个随机字符串,以便相似的密码在数据库中看起来不相同。但是,如果盐不是每个用户独有的(即:您使用硬编码的盐),那么您几乎已经使您的盐变得毫无价值。因为一旦攻击者找出了一个密码盐,他就拥有了所有密码盐。
创建 salt 时,请确保它对要加盐的密码是唯一的,然后将完成的哈希值和盐都存储在数据库中。这样做的目的是使攻击者必须单独破解每个盐和哈希,然后才能获得访问权限。这意味着攻击者需要付出更多的工作和时间。
用户创建密码
如果用户通过前端创建密码,则意味着必须将其发送到服务器。这会带来一个安全问题,因为这意味着未加密的密码正在被发送到服务器,如果攻击者能够监听和访问,那么您在 PHP 中的所有安全性都毫无价值。始终安全地传输数据,这是通过SSL完成的,但即使SSL也不是完美无缺的(OpenSSL的Heartbleed缺陷就是一个例子)。
还要让用户创建一个安全的密码,这很简单,应该始终这样做,用户最终会感激不尽。
最后,无论您采取何种安全措施,没有什么是 100% 安全的,保护技术越先进,攻击就越先进。但是,遵循这些步骤将使您的网站更加安全,并且攻击者更不希望这样做。
这是一个PHP类,可以轻松地为密码创建哈希和盐
评论
从 PHP 5.5 开始,PHP 具有简单、安全的函数,用于散列和验证密码、password_hash() 和 password_verify()
$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));
password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false
使用时,它会生成一个随机盐,并将其包含在输出的哈希值中(以及使用的成本和算法)。 然后读取该哈希并确定使用的 salt 和加密方法,并根据提供的明文密码对其进行验证。password_hash()
password_verify()
提供指示 PHP 使用已安装 PHP 版本的默认哈希算法。确切地说,这意味着哪种算法将在未来的版本中随着时间的推移而改变,因此它将始终是最强大的可用算法之一。PASSWORD_DEFAULT
增加成本(默认为 10)会使哈希更难暴力破解,但也意味着生成哈希并针对它们验证密码对服务器的 CPU 来说将是一项更大的工作。
请注意,即使默认哈希算法可能会更改,旧哈希将继续进行验证,因为使用的算法存储在哈希中并拾取它。password_verify()
还行 在 Fitsy 中,我们需要盐 盐必须是唯一的 所以让我们生成它
/**
* Generating string
* @param $size
* @return string
*/
function Uniwur_string($size){
$text = md5(uniqid(rand(), TRUE));
RETURN substr($text, 0, $size);
}
我们还需要哈希 我正在使用 sha512 它是最好的,它是在PHP中
/**
* Hashing string
* @param $string
* @return string
*/
function hash($string){
return hash('sha512', $string);
}
所以现在我们可以使用这个函数来生成安全密码
// generating unique password
$password = Uniwur_string(20); // or you can add manual password
// generating 32 character salt
$salt = Uniwur_string(32);
// now we can manipulate this informations
// hashin salt for safe
$hash_salt = hash($salt);
// hashing password
$hash_psw = hash($password.$hash_salt);
现在我们需要在数据库中保存我们的 $hash_psw 变量值和$salt变量
对于授权,我们将使用相同的步骤...
这是保护客户密码的最佳方式......
P.s. 对于最后 2 个步骤,您可以使用自己的算法...... 但请确保您将来可以生成此哈希密码 当您需要授权用户时...
评论
sha512
评论