【发布时间】:2017-11-24 17:25:52
【问题描述】:
我编写了一些基于 PHP5 的 password_hash 和 password_verify 函数的 JS 函数。它基本上只是一种更简单的方法来生成使用随机盐散列的密码,并验证所述密码,而无需单独存储盐。
function passwordHash ( password ) {
if( ! password )
throw new Error('No password was given to hash')
if( ! _.isString( password ) )
throw new Error('Must provide a STRING as a password')
// Generate the salt
// THIS MUST NOT CHANGE! If this value is not the same as what
// passwordVerify expects, no hash will be validated
const salt = randStr( 20 )
// Return the salted hash with the salt prepended to it
return salt + makeHash( password, salt )
}
function passwordVerify ( password, passwdHash ) {
if( ! password || ! passwdHash )
throw new Error('Need to provide both a password and a hash to verify')
if( ! _.isString( password ) || ! _.isString( passwdHash ) )
throw new Error('Password and hash both need to be strings')
// If the hash isn't even the proper length, don't bother checking
if( passwdHash.length !== 108 )
return false
// Get the salt from the password hash - first 20 chars
const salt = passwdHash.substr( 0, 20 )
// Get the password hash, everything after the first 20 chars
const hash = passwdHash.substr( 20 )
// Check the hash against a hash generated with the same data
return makeHash( password, salt ) === hash
}
function makeHash ( str, salt ) {
if( ! _.isString( str ) || ! _.isString( salt ))
throw new Error('_.hash() requires two string parameters, a string to hash and a salt')
const h = crypto.createHash('sha512')
h.update(str)
h.update(salt)
return h.digest('base64')
}
这是一个使用示例:
<!-- language: lang-js -->
const hash = _.passwordHash( 'secret' )
_.passwordVerify( 'secret', hash ) === true
_.passwordVerify( 'terces', hash ) === false
我也在寻找一种在哈希中包含到期日期的方法,这意味着如果在生成哈希时提供了日期,那么最后期限将包含在哈希中(所以不是纯文本)。示例:
<!-- language: lang-js -->
const hash = _.passwordHash({
'password' : 'secret',
'expiration' : new Date(new Date().getTime() + (24 * 60 * 60 * 1000))
})
// If ran within 24 hours of when it was generated
_.passwordVerify( 'secret', hash ) === true
// If ran later than 24 hours after it was generated
_.passwordVerify( 'secret', hash ) === false
但我找不到一致的方法来在哈希中包含日期,该日期将拒绝正确的密码在所述日期之后。我想我可以在密码本身旁边存储一个哈希版本的截止日期,但这不会太难利用。
我们将不胜感激。
谢谢!
【问题讨论】:
-
为什么?只需单独存储日期即可。
-
使用
password_hash和password_verify,您不需要提供盐,这甚至不鼓励,因此无需单独保存盐。但这些函数并不安全,没有迭代或其他方法来确保最小哈希 CPU 时间,详情请参阅下面的评论。 -
仅使用散列函数是不够的,仅添加盐对提高安全性无济于事。而是使用随机盐迭代 HMAC 约 100 毫秒的持续时间,然后将盐与哈希一起保存。使用
PBKDF2、Rfc2898DeriveBytes、password_hash、Bcrypt等函数或类似函数。关键是让攻击者花费大量时间通过蛮力寻找密码。
标签: javascript hash ecmascript-6 passwords salt