Home > Software engineering >  How to use bcrypt to encrypt a date and decrypt it for comparison?
How to use bcrypt to encrypt a date and decrypt it for comparison?

Time:10-29

I am sending a token to user email like below and using bcrypt for this as an encrypt/decrypt mechanism.

  const token = await bcrypt.hash(joinDate, 10);

When the user clicks on the link in email, I get the above token back as that token is a part of /api/unsubscribe?userId="abcd"&token="token_that_was_generated_using_bcrypt_and_sent_to_user"

const {userId, token} = req.query;

In the api, I am comparing joinDate obtained from database vs token sent by req.query but it never matches.

const joinDate = user.joinDate.toString();
const tokenValidated = await bcrypt.compare(joinDate, token)//this is always false although us generated from same joinDate field

Why is tokenValidated always false although it was generated using the same field joinDate?

CodePudding user response:

Your use of bcrypt is not secure. Anyone can brute-force a few hundred or a few thousand dates and cause any user to become unsubscribed.

I assume your motivation is to avoid having to create a new table in your database and store a random token for every email you've sent out.

If so, the proper tool to use is HMAC.

Your URL should be of the form: /api/unsubscribe?userId=abcd&mac=....

Come up with a secret key known only to your server. This secret key will be used to create and authenticate all unsubscribe requests. Only use this key for authenticating unsubscribe requests.

Perform HMAC-SHA512 on the user id, with the HMAC output truncated to 128 bits. Then base64-encode the 128 bits and set it as the mac parameter in the URL.

HMAC means to create a hash-based message authentication code, which will confirm to your server that it must have created and emailed out that 'mac'.

Now, your server can authenticate each response, because only someone with knowledge of the server's secret key can produce a valid unsubscribe link.

CodePudding user response:

Your logic of using bcrypt for hash and verifying on the other end should work. The only possible thing that can prevent it from working is either:

1 - the joinDate here: const token = await bcrypt.hash(joinDate, 10);

is not ===

to joinDate here:const tokenValidated = await bcrypt.compare(joinDate, token)

( maybe differes in ", ' or different format orsomething )

2 - or the token is kinda different in ' or " when passing through / read from queryparam; (e.g. you token is going "'token_that_was_generated_using_bcrypt_and_sent_to_user'" for comparison.)

  • Related