【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
当前据说MD5部分不安全。 考虑到这一点,我想知道使用哪种机制进行密码保护。
这个问题, “双重哈希”密码是否比仅哈希一次密码安全? 建议多次散列可能是一个好主意,而如何对单个文件实施密码保护? 建议使用盐。
我正在使用PHP。 我想要一个安全,快速的密码加密系统。 将密码哈希一百万次可能更安全,但也更慢。 如何在速度和安全性之间取得良好的平衡? 另外,我希望结果具有恒定数量的字符。
- 哈希机制必须在PHP中可用
- 必须安全
- 它可以使用盐(在这种情况下,所有盐都一样好吗?是否有任何方法可以生成优质盐?)
另外,我是否应该在数据库中存储两个字段(例如,一个使用MD5,另一个使用SHA)? 它会使它更安全或更不安全吗?
如果我不够清楚,我想知道要使用哪个哈希函数以及如何选择合适的盐,以便拥有安全,快速的密码保护机制。
尚未完全涵盖我的问题的相关问题:
PHP中的SHA和MD5有什么区别
简单密码加密
安全的asp.net密钥,密码存储方法
您将如何在Tomcat 5.5中实现盐腌密码
#1楼
我正在使用Phpass ,这是一个简单的单文件PHP类,几乎可以在每个PHP项目中轻松实现。 另请参见H。
默认情况下,它使用Phpass中实现的最强大的可用加密,该加密是bcrypt并回退到MD5等其他加密,以向与Wordpress之类的框架提供向后兼容性。
返回的哈希可以原样存储在数据库中。 生成哈希的示例用法是:
$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);
要验证密码,可以使用:
$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);
#2楼
我只想指出,PHP 5.5包含一个密码哈希API ,该API为crypt()提供了包装器。 该API大大简化了哈希,验证和重新哈希密码哈希的任务。 作者还发布了一个兼容性包 (以您只require使用的单个password.php文件的形式),适用于使用PHP 5.3.7及更高版本并希望立即使用此功能的用户。
它目前仅支持BCRYPT,但是它旨在易于扩展以包括其他密码哈希技术,并且由于该技术和成本是作为哈希的一部分存储的,因此,对您喜欢的哈希技术/成本的更改不会使当前哈希无效将自动验证,使用正确的技术/成本。 如果您未明确定义自己的盐,它还会处理生成“安全”盐的问题。
该API公开了四个功能:
-
password_get_info()-返回有关给定哈希的信息 -
password_hash()-创建密码哈希 -
password_needs_rehash()-检查给定的哈希值是否与给定的选项匹配。 有用的检查哈希是否符合您当前的技术/成本方案,允许您在必要时重新哈希 -
password_verify()-验证密码是否与哈希匹配
目前,这些函数接受PASSWORD_BCRYPT和PASSWORD_DEFAULT密码常量,它们现在是同义词,不同之处在于PASSWORD_DEFAULT“如果支持更新的,更强大的哈希算法,则在更新的PHP版本中可能会更改”。 在登录时使用PASSWORD_DEFAULT和password_needs_rehash()(并在必要时进行重新哈希处理)应确保您的散列具有相当强的抵御暴力攻击的能力,而对您几乎没有任何帮助。
编辑:我刚刚意识到,这是罗伯特·K的答案中简要提到的。 我将在这里保留这个答案,因为我认为它为不了解安全性的人提供了更多有关其工作方式和易用性的信息。
#3楼
我在这里找到了关于此问题的完美话题: 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));
}
?>
#4楼
尽管已经回答了问题,但我只想重申,用于哈希处理的盐应该是随机的,而不是像第一个答案中所建议的电子邮件地址那样。
有关更多说明,请访问-http : //www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/
最近,我讨论了用随机位加盐的密码散列是否比用可猜测或已知盐加盐的密码散列更安全。 让我们看看:如果存储密码的系统以及存储随机盐的系统遭到破坏,则攻击者将可以访问哈希和盐,因此盐是否是随机的都没有关系。 攻击者可以生成预先计算的彩虹表来破解哈希。 有趣的部分来了-生成预先计算的表并不是那么简单。 让我们以WPA安全模型为例。 实际上,您的WPA密码永远不会发送到Wireless Access Point。 而是使用您的SSID(网络名称,如Linksys,Dlink等)进行哈希处理。 这是一个很好的解释。 为了从哈希中检索密码,您将需要知道密码以及盐(网络名称)。 Wifi教堂已经预先计算了哈希表,该哈希表具有前1000个SSID和大约一百万个密码。 所有表的大小约为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亿)次迭代。
#5楼
谨记
关于PHP的密码加密,已经有很多说法,其中大多数是非常好的建议,但是在您甚至开始使用PHP进行密码加密的过程之前,请确保已实现或准备好实现以下内容。
服务器
港口
如果您没有正确保护运行PHP和DB的服务器的安全性,那么加密的效果如何,都将毫无用处。 大多数服务器以相对相同的方式运行,它们分配有端口,以使您可以通过ftp或shell远程访问它们。 确保更改了活动的远程连接的默认端口。 通过不这样做,您实际上使攻击者在访问系统时少了一步。
用户名
对于世界上所有好的东西,请勿使用用户名admin,root或类似名称。 另外,如果您使用的是基于UNIX的系统,请不要使root帐户登录名不可访问,它应该始终仅是sudo。
密码
您告诉用户输入正确的密码以避免被黑,请执行相同的操作。 后门完全打开时,进行所有锁定前门的努力的意义何在?
数据库
服务器
理想情况下,您要将数据库和应用程序放在单独的服务器上。 由于成本原因,这并非总是可能的,但是它确实可以保证一定的安全性,因为攻击者必须经过两个步骤才能完全访问系统。
用户
始终让您的应用程序拥有其自己的帐户来访问数据库,并仅为其提供所需的特权。
然后为您提供一个单独的用户帐户,该帐户不会存储在服务器上的任何位置,甚至不会存储在应用程序中。
像往常一样,不要使这个根或类似的东西。
密码
请遵循与所有正确密码相同的准则。 另外,请勿在同一系统上的任何SERVER或DB帐户上重复使用相同的密码。
的PHP
密码
永远不要在数据库中存储密码,而要存储哈希和唯一的盐,稍后我将解释原因。
散列
单向哈希!!!!!!!,永远不要以可以反转的方式哈希密码,哈希应该是一种方式,这意味着您不要反转并将它们与密码进行比较,而是哈希输入的密码以相同的方式比较两个哈希值。 这意味着,即使攻击者可以访问数据库,他也不知道实际的密码是什么,而只是密码所产生的哈希值。 这意味着在最坏的情况下为用户提供更高的安全性。
那里有很多很好的哈希函数( password_hash , hash等),但是您需要选择一个好的算法才能使哈希有效。 (bcrypt及其类似的算法是不错的算法。)
当散列速度是关键时,速度越慢越能抵抗暴力攻击。
散列中最常见的错误之一是散列不是用户独有的。 这主要是因为不是唯一地产生盐。
盐
密码在散列前应先加盐。 Salting为密码添加了一个随机字符串,因此相似的密码在数据库中不会显示相同的密码。 但是,如果盐不是每个用户都唯一的盐(即:您使用硬编码盐),那么您几乎会使盐变得一文不值了。 因为一旦攻击者找出了一个密码盐,他就对所有密码都加盐。
创建盐时,请确保它与盐盐密码唯一,然后将完整的哈希和盐盐都存储在数据库中。 这样做是为了使攻击者必须先破解每种盐和哈希,然后才能获得访问权限。 对于攻击者来说,这意味着更多的工作和时间。
用户创建密码
如果用户正在通过前端创建密码,则意味着必须将其发送到服务器。 这带来了一个安全问题,因为这意味着未加密的密码将发送到服务器,并且如果攻击者能够侦听和访问,则您在PHP中的所有安全性都毫无用处。 总是安全地传输数据,这是通过SSL来完成的,但是即使SSL并非完美无缺,也要感到厌倦(OpenSSL的Heartbleed缺陷就是一个例子)。
还要使用户创建一个安全的密码,这很简单,应该始终这样做,最终用户将不胜感激。
最后,无论您采取什么安全措施都是100%安全,防护技术越先进,攻击就变得越先进。 但是,按照以下步骤操作将使您的站点更安全,而攻击者则更不希望这样做。
这是一个PHP类,可轻松为密码创建哈希和盐
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3141830