I am trying to easily generate an unsubscribe link without having to have per-user secret. My proposal is to send sha512(email shared_secret)
as an "unsubscribe token".
Given user knows clear text of email
as well as sha512(email)
, is this safe or does it make easier for an attacker to guess shared_secret
?
CodePudding user response:
Think about what you are trying to achieve. You generate a token, and when you receive it back from an untrusted source, you want to make sure that the token is in fact the one generated by you, without storing it yourself.
The cryptographic tool for this is a message authentication code, like HMAC. Without going into too much detail, HMAC is about hashing your data with a secret included, similar to what you proposed, but in a way that is actually secure against a whole range of attacks. So in a still naive implementation, you could generate a HMAC(email, shared_secret) and send that as your unsubscribe token.
However, the usual problem with HMAC if implemented incorrectly is replay. This token will only depend on the user's email address and nothing else. If this email address ever unsubscribes and receives a token (that might also get compromised), that token is forever valid to unsubscribe that email address, ie. can be replayed by an attacker. In case of a plain unsubscribe link in a not very critical application, this can be an acceptable risk, or you can implement it better. For example you could have a timestamp (eg. as unixtime) also added to the mix and generate the code as [timestamp, HMAC(email timestamp, secret)], ie. you would include the timestamp in the code, and also add it to your unsubscribe link plaintext. When the server receives the unsubscribe request, it can regenerate the HMAC, check if it's the same, and also check the timestamp so that it's not too old. The benefit of this is that it's still stateless, and reasonably secure for most applications.
Or you can just store a unique token for your users, which would of course be the most secure for multiple reasons (mostly because of less complexity and the smallest attack surface), but stateful.
CodePudding user response:
Never ever publish even encrypted secrets if unnecessary. In comparison of not sending the encrypted secret and sending it, not sending the encrypted secret is obviously better. Imagine if a user registrates with multiple accounts and unsubscribes with all of them. He/she may guess the formula of your input and if so, he/she will know that the resulting value differs only in the email in its input. By varying the emails, maybe 100 emails, this may lead closer into hacking you. Instead, I recommend the generation of a token, uniquely identifying a user in some manner and sending that token to the user. The token should not rely on information you do not intend to share. It could rely on id, email and a salt.