【问题标题】:Best way to incorporate a password expiration date within the password hash在密码哈希中包含密码到期日期的最佳方法
【发布时间】:2017-11-24 17:25:52
【问题描述】:

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

但我找不到一致的方法来在哈希中包含日期,该日期将拒绝正确的密码所述日期之后。我想我可以在密码本身旁边存储一个哈希版本的截止日期,但这不会太难利用。

我们将不胜感激。

谢谢!

【问题讨论】:

  • 为什么?只需单独存储日期即可。
  • 使用password_hashpassword_verify,您不需要提供盐,这甚至不鼓励,因此无需单独保存盐。但这些函数并不安全,没有迭代或其他方法来确保最小哈希 CPU 时间,详情请参阅下面的评论。
  • 仅使用散列函数是不够的,仅添加盐对提高安全性无济于事。而是使用随机盐迭代 HMAC 约 100 毫秒的持续时间,然后将盐与哈希一起保存。使用PBKDF2Rfc2898DeriveBytespassword_hashBcrypt 等函数或类似函数。关键是让攻击者花费大量时间通过蛮力寻找密码。

标签: javascript hash ecmascript-6 passwords salt


【解决方案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!");

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

【讨论】:

  • 这不安全,没有迭代或其他方法来确保最小哈希 CPU 时间。
  • @zaph 我认为这与问题无关。您已经在 cmets 中指出了这一点,我认为我不需要在回答中重复您的建议
  • 密码安全与问题有关。此外,我认为不安全密码处理的另一个例子不是一件好事,对于密码处理不当的用户来说,这当然不是一件好事。
  • @zaph 不。有人需要先将 phps 实现转译为 JS
  • @zaph 回到你的第一点:代码不包含任何散列。它只是提供对 OPs 代码的引用,后面直接跟您的评论。所以没有必要指出 hashing security 因为我的答案不包含任何 hashing
猜你喜欢
  • 2013-12-09
  • 2018-10-31
  • 2011-09-22
  • 2012-06-23
  • 1970-01-01
  • 2010-10-16
  • 2020-12-17
  • 2020-04-27
相关资源
最近更新 更多