在密码哈希中包含密码到期日期的最佳方法

时间:2017-06-21 17:13:20

标签: javascript hash ecmascript-6 passwords salt

我编写了一些基于PHP5 password_hashpassword_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

但是我无法找到一种一致的方法来在哈希中包含一个日期,该日期会在所述日期之后拒绝正确的密码。我当时认为我可以在密码本身旁边存储一个最后期限的哈希版本,但这不会太难开发。

任何意见都会受到赞赏。

谢谢!

1 个答案:

答案 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!");

您可以考虑另外存储时间,或者如果您想要第三方身份验证,则可以创建令牌。