我编写了一些基于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
但是我无法找到一种一致的方法来在哈希中包含一个日期,该日期会在所述日期之后拒绝正确的密码。我当时认为我可以在密码本身旁边存储一个最后期限的哈希版本,但这不会太难开发。
任何意见都会受到赞赏。
谢谢!
答案 0 :(得分:-1)
只需使用当前时间哈希密码,例如:
function passwordHash ( password ) {
const salt = (+new Date()+"T"+randStr(20)).slice(20);//make shure salt has const length (may increase length due to lowered entropy)
// Return the salted hash with the salt prepended to it
return salt + makeHash( password, salt )
}
所以现在密码用当前时间进行哈希处理,因此您可以正常验证哈希值。要检查时间,您可以:
const salt = passwdHash.substr( 0, 20 );
const time=+salt.split("T")[0];
//range check
if(time<+new Date()) throw new Error("Token expired!");
您可以考虑另外存储时间,或者如果您想要第三方身份验证,则可以创建令牌。