我正在使用各种不安全/可怕的不安全的基于MD5的密码哈希更新几个项目.我现在至少对最佳做法有所了解,但我仍然想知道我做错了什么.我还没有看到我在其他地方使用的具体过程,但至少有一个SO用户似乎想要做类似的事情.就我而言:
密码哈希是使用bcrypt生成的.(因为正确的选项似乎是bcrypt,scrypt,或者pbkdf2和bcrypt在PHP中最容易被我访问.)
每个哈希使用不同的随机盐.(防止攻击者生成使用单个静态盐计算的自定义彩虹表.)
散列,算法设置和salt存储在一起.(因为这就是PHP的crypt函数给我的哈希值.)
成功登录后,将使用新的随机盐重新计算哈希值.
这是我想知道的最后一步.我的目的是随着时间的推移允许更新散列算法,以便定期登录的用户将以最安全的格式存储密码.
我的问题是:
这是浪费时间吗?
这样做有危险吗?
我正在考虑使用两个不同的salt字符串哈希用户密码,一个存储在代码中,对于所有用户都是相同的,另一个存储在数据库中,每个用户都有自己唯一的值.
这比仅仅将值存储在数据库中更有效吗?
任何建议,意见相关.
谢谢
我昨天在这里,得到了一些非常好的答案.我把我得到的东西放在一起,我认为这将是一个相当安全的算法.我在使用带有生成盐的for循环的河豚时遇到了问题.
我正在使用base64字符和for循环来获取随机字符串.我想把这个生成的字符串作为salt插入到crypt函数中.
因为关于河豚的文档非常稀疏,PHP文档甚至没有提到它,所以我在这里黑暗中刺伤.
真正奇怪的是,如果您按照现在的方式运行此代码,它将不会失败.除去任一的"$ 2A $ $ 07"从上面的for循环或从crypt函数,它会间歇性地返回一个加密的字符串.我对河豚的理解是,加密的字符串必须以'$ 2a $ 07 $'开头,以$'结尾,因此在crypt函数中连接.我真的不需要for循环之上的开始字符串而只是想得到摆脱它.
我还想澄清关于在数据库中存储随机盐的最佳实践,还是将crypt函数的输出存储在数据库中?
昨天,没有真正的代码被抛出,只是讨论.我今天想把一些代码放在一起,并且有一些相当安全的东西.如果有人能想出更好的算法,我总是敞开心扉.
$base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$salt = '$2a$07$';
for($i=0; $i<60; $i++)
{
$salt .= $base64[rand(0,63)];
}
return crypt('password', '$2a$07$'.$salt.'$');
Run Code Online (Sandbox Code Playgroud) 我有一个简单的应用程序,我可以注册用户并验证它们.我已经使用密码编码并成功验证了它们.我在我的应用程序中使用Spring 3,Spring Security 3和Hibernate 3.
现在我想用他们的用户ID来限制他们的密码,但是我无法实现这个功能.有人可以帮我实现吗?我一直试图这么做但却无法完成它.
这是我用来为用户提供ID并对其进行身份验证的代码.
XYZ-security.xml文件
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/welcome.do" access="hasRole('ROLE_USER')" />
<form-login login-page="/login.do" authentication-failure-url="/login.do?login_error=1"/>
<logout invalidate-session="true" logout-url="/logout" logout-success-url="/"/>
</http>
<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
<beans:bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="daoAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder ref="passwordEncoder">
<salt-source ref="saltSource"/>
</password-encoder>
</authentication-provider>
</authentication-manager>
<!-- For hashing and salting user passwords -->
<beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>
<beans:bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource"
p:userPropertyToUse="id"/>
Run Code Online (Sandbox Code Playgroud)
UserDetailsAdapter.java
@Service("userDetailsAdapter")
public class UserDetailsAdapter {
private Long id;
org.springframework.security.core.userdetails.User buildUserFromUserEntity(User userEntity) { …Run Code Online (Sandbox Code Playgroud) 我错过了什么吗?是否有任何其他步骤存储数据库的密码?
存储密码:
经过尽可能多的研究,我得出的结论是,在Web应用程序数据库(在我的例子中是MySQL + PHP)中存储用户密码的最佳方法如下:
攻击#1: 攻击者通过SQL注入转储数据库.
我们的hash_function的DB结果和每用户盐的随机数.
转储后,攻击者可以通过查找自己的帐户获取$ userPassword和 $ randomSalt.然后通过猜测md5等哈希函数,他可以在$ sitewideSalt上开始彩虹攻击 .但这可能需要1.41亿个世纪[1].
通过使用此类安全性,不允许转储数据库来破坏存储的密码.用户仍然必须通过另一种方法找到$ sitewideSalt.
攻击#2: 攻击者找到本地文件包含(LFI)向量.
攻击者可以获取我们的Web应用程序的原始代码.
在通过可能的LFI或RFI [2]利用Web应用程序之后,攻击者读取我们的Web应用程序的源代码并获得我们的简单算法和存储的
$ sitewideSalt.
下一步去哪儿?
现在,攻击者拥有他可以开始彩虹的两种盐来获取实际的密码.除非他必须为每个用户制作1个彩虹表,因为每个用户都有不同的随机用户特定盐($ randomSalt).
"现代服务器可以计算每秒大约330MB的MD5哈希值.如果您的用户拥有小写,字母数字和6个字符长的密码,您可以在大约40秒内尝试每个可能的密码."
"...... CUDA,你可以将自己的小型超级计算机集群放在一起,让你每秒可以尝试大约700,000,000个密码......"[3]
我们现在需要做的是使用耗时的算法扩展散列函数,例如bcrypt.bcrypt的工作负载因子可以是更简单的散列函数的5-6个数量级.破解一个密码可能需要数年而不是几分钟.并且作为奖励,bcrypt已经为每个哈希生成随机盐并将其存储在结果哈希中.
我正在尝试为我的密码正确地执行每个用户和站点范围的盐.这是我得到的:
require('../../salt.php'); //this is above the web root and provides $salt variable
$pw = mysql_real_escape_string($_POST['pw']);
$per_user_salt = uniqid(mt_rand());
$site_salt = $salt //from salt.php that was required on first line
$combine = $pw . $per_user_salt . $site_salt;
$pw_to_put_in_db = hash("sha512", $combine);
Run Code Online (Sandbox Code Playgroud)
这是正确的吗?谢谢
好吧,原来我在加密/解密时很糟糕.我只是不明白.我怎样才能使Java加密String message1 = "hello world";与String salt = "mySalt";使用AES加密?加密后如何解密?
如果你有时间提供最基本的代码,它会对我有很大的帮助.
另外一个关于AES加密的一般问题,使用相同的盐,同一条消息总是会有相同的加密吗?
提前致谢.
我是C#的新手,这是我在这里的第一个问题,所以我提前为任何失礼道歉.
语境:
当用户注册时,我调用CreateSaltedHash()方法并从文本字段中传递用户输入的密码.在将密码存储在User表的Password列中之前,此方法会对密码进行加密和哈希处理.
题:
当用户尝试登录时,我该如何验证密码?
如果我再次调用CreateSaltedHash()方法,由于随机盐,它将不匹配.
我应该将盐储存在单独的栏中吗?我应该在生成盐渍哈希时使用分隔符吗?根据盐渍和散列密码验证输入密码的最安全方法是什么?
代码: 这是我到目前为止所拥有的.
public class PasswordHash
{
public const int SALT_BYTES = 32;
/*
* Method to create a salted hash
*/
public static byte[] CreateSaltedHash(string password)
{
RNGCryptoServiceProvider randromNumberGenerator = new RNGCryptoServiceProvider();
byte[] salt = new byte[SALT_BYTES];
randromNumberGenerator.GetBytes(salt);
HashAlgorithm hashAlgorithm = new SHA256Managed();
byte[] passwordByteArray = Encoding.UTF8.GetBytes(password);
byte[] passwordAndSalt = new byte[passwordByteArray.Length + SALT_BYTES];
for (int i = 0; i < passwordByteArray.Length; i++)
{
passwordAndSalt[i] = passwordByteArray[i];
}
for (int i = 0; …Run Code Online (Sandbox Code Playgroud) 我正在寻找一种简单,安全的解决方案,用于使用Node存储用户的密码.我是加密新手,但一直试图通过在线研究将解决方案整合在一起.我正在寻找验证,我提出的是一个基本(不是银行,医院等)安全需求的Web应用程序的可靠解决方案.这里是:
var crypto = require('crypto');
var SALT_LENGTH = 64;
var KEY_LENGTH = 64;
var ITERATIONS = 1000;
function createHashedPassword(plainTextPassword, cb) {
crypto.randomBytes(SALT_LENGTH, function (err, salt) {
console.time('password-hash');
crypto.pbkdf2(plainTextPassword, salt, ITERATIONS, KEY_LENGTH, function (err, derivedKey) {
console.timeEnd('password-hash');
return cb(null, {derivedKey: derivedKey, salt: salt, iterations: ITERATIONS});
});
});
};
Run Code Online (Sandbox Code Playgroud)
......这是我做出的选择让我达到了这一点:
使用什么哈希算法?
基于这篇被广泛引用的文章,看起来主要的竞争者是PBKDF2,bcrypt和scrypt.我选择了PBKDF2,因为它内置了Node支持.
什么盐的大小?
这个堆栈溢出答案似乎是我能找到的最直接的答案.我仍然不太清楚为什么64字节是正确的盐大小.当我谷歌的时候,我得到一个叠层交换答案像这样,但我不知道它适用于节点的算法?在这里完全混淆,针对使用此节点功能的新手的解释将是非常棒的.
使用什么密钥长度?
再一次,我的选择主要取决于上面的相同答案,但我对"为什么"的基本知识一模糊.答案是"生成小于输入的密钥是浪费,所以至少要使用64个字节".咦?再一次,实际的解释会有所帮助.
要使用多少次迭代?
对于这个问题,我根据这个堆栈交换答案做出了我的选择.我不太了解它,但我确实认为该算法大约需要8ms.所以,正如你所看到的那样,我将定时器放在函数上,并且我调整了迭代次数,以便在我的机器上进行调整.
谢谢!