使用bcrypt哈希令牌并通过再次升级秘密字符串来验证它

发布于 2025-02-13 23:08:25 字数 2522 浏览 0 评论 0原文

据我了解,如果攻击者获取用于更改用户密码并验证电子邮件的令牌,则数据库中的令牌是不安全的,那么他们可以做所有这些。

因此,现在我试图在DB中放置令牌,与密码一样。 fiy,令牌是通过电子邮件发送给用户的,作为一个看起来像这样的URL:https://myurl.com/whate/uid/tokentext其中uid uid and 代码> tokentext 分别是用户ID和令牌。

并将令牌保存在DB中,上面有三个字段:IDHashedTokenuserId

为了验证令牌,有一种简单的方法,即检索用户ID(URL中的uid),对于每个用户都具有的令牌,运行bcrypt.compare(tokentext,hashedtoken)

但是,这样我将至少需要两个DB查询,也许需要一些bcrypt.compare调用。

我想到的另一种方式是获得tokentext,哈希,然后通过检查HashedToken等于我刚刚生成的一个来运行数据库搜索。

这就是我产生令牌的方式:

TokenSchema.statics.generateToken = async function(user){
        const tokenSecret = crypto.randomBytes(16).toString('hex');                                  
        const newToken = new this({                                                                  
                _userId: user._id,
                token: tokenSecret,                                                                  
        });                                                                                          
        
        await newToken.save();
}

这就是保存的方式(请注意,在插入到db之前是哈希的):

TokenSchema.pre('save', function(next){
        var token = this;

        //Note: no salting is needed since we can assume that token texts will be unique
        bcrypt.hash(token.token, 0, function(err, hash){
                if(err){
                        return next(err);
                }

                token.token = hash;
                next();
        })
})

这就是我的验证方式:

TokenSchema.statics.validateToken = async function(userId, tokenSecret){                             
        const hash = await bcrypt.hash(tokenSecret, 0);                                              
        token = await Token.findOneAndDelete({token: hash, _userId: userId});                        
        if(!token){                                                                                  
                throw new Error('Token not found');                                                  
        }                                                                                            
}

我认为令牌是独一无二的,因此不需要盐水,所以我认为我认为当我重新运行哈希时,我会得到相同的结果,但是不,对于相同的tokensecret,我会得到不同的哈希。

在这种情况下,我无法运行bcrypt.compare,因为它应该是查询的一部分,并且比较DB的所有令牌都会非常慢。

有什么想法我在做什么错?如果我不使用盐,为什么不可能比较两个哈希?

As I understand, having the token in plain text in the Database is not secure, if an attacker gets the tokens that I use for changing the user passwords and verifying the email, then they could do all those.

So now I am trying to hash the tokens in the DB, same as I do with the passwords. FIY, the tokens are sent to the user by email as an URL that looks like this: https://myurl.com/whatever/uid/tokentext where uid and tokentext are the user id and token before being hashed respectively.

And the tokens are saved in the DB with three fields: id, hashedToken, userId.

For verifying a token, there is an easy way of doing it, which is, retrieving the user id (uid in the URL), and for each token this user has, run bcrypt.compare(tokenText, hashedToken)

But this way I would need at least two DB queries and maybe a few of bcrypt.compare calls.

The other way I have thought of is to get the tokenText, hash it and then run the Database search by checking that the hashedToken equals the one I just generated.

This is how I generate the token:

TokenSchema.statics.generateToken = async function(user){
        const tokenSecret = crypto.randomBytes(16).toString('hex');                                  
        const newToken = new this({                                                                  
                _userId: user._id,
                token: tokenSecret,                                                                  
        });                                                                                          
        
        await newToken.save();
}

This is how it is saved (note that it is hashed before inserting to DB):

TokenSchema.pre('save', function(next){
        var token = this;

        //Note: no salting is needed since we can assume that token texts will be unique
        bcrypt.hash(token.token, 0, function(err, hash){
                if(err){
                        return next(err);
                }

                token.token = hash;
                next();
        })
})

And this is how I verify:

TokenSchema.statics.validateToken = async function(userId, tokenSecret){                             
        const hash = await bcrypt.hash(tokenSecret, 0);                                              
        token = await Token.findOneAndDelete({token: hash, _userId: userId});                        
        if(!token){                                                                                  
                throw new Error('Token not found');                                                  
        }                                                                                            
}

I thought the tokens would be unique, so no need for salting, so I thought I would get the same result when I re-run the hash, but no, I get different hashes for the same tokenSecret.

In this case, I can't run bcrypt.compare since it should be part of the query, and comparing ALL the tokens of the DB will be really slow anyways.

Any ideas what am I doing wrong? Why isn't it possible to compare both hashes if I'm not using salt?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风筝在阴天搁浅。 2025-02-20 23:08:25

每次您打电话时,BCrypt都会返回不同的哈希。这就是BCrypt的设计方式,这帮助使HASH获得了保护。

请使用比较或使用不同的哈希算法。

bcrypt returns different hashes every time you make a call. This is how bcrypt was designed, This help makes the hash secured.

please use the compare or use a different hashing algorithm.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文