How to prevent HMAC replay in Websockets
Hi there. I'm currently looking into novu and tried to find out more details on how authentication works.
I was able to some information on HMAC in the documentation: https://docs.novu.co/notification-center/client/headless/get-started#hmac-encryption. As far as I understand one would use a backend service that is able to check the authentication status of a user to generate an HMAC which uses an API key from novu as a secret. As far as I understand this HMAC would be static for any given subscriber id as long as the API key is not being rotated.
I don't really understand the benefits of using HMAC in this scenario, other than making it harder (/impossible) to guess the credentials which would also be the case e.g. using uuid subscriber ids. If someone is able to access the subscriber id and HMAC he will be able to connect.
Is there any replay prevention available? For example using a timestamp? Is there any other method to authenticate a subscriber?
3 Replies
Hey @jnugh, that's a great question! First of all let me add @Dima Grossman who can help us navigate to the right person about this.
Now to the way I see it, you are 100% HMAC is a great solution to prevent sniffing credentials, prevent user user impersonation (assuming you don't have the secret key as well), and is a good practice of transfer level encryption. In the case you are mentioning (both user id as well as secret app) another validation is needed, and a state-full solution (sessions, hash table), or a state-less (JWT style) are needed, and with combination of time based you can get to a higher level of security in the expanse of performance (more time is needed to validate those with the backend).
Would you mind sharing some more about the case you are looking into? What's the risk you are trying to mitigate?
Let’s say there is a user A who uses our service. User A gets compromised somehow maybe a cross site scripting in our app or malware on the users computer (or anything else). Now an attacker knows the subscriber is and the MAC that has been generated using the secret and the subscriber id. The only way to restore the users security would be to rotate the secret which would be the API key. This is shared across all users so changing the api key would invalidate all other users jamb. It would also require a config change on our backend system.
This is why MACs are often designed to be non replayable - an old MAC can not be used to access the same resource again. So after the user account has been secured the old HMAC does not give the attacker access to new notifications.
This is often done by adding a timestamp to the HMAC, compare the timestamp with the current time and only validate the HMAC if it was created recently. We use a token based system where an access token is only valid for a few minutes and refresh tokens can be invalidated. Having a replayable HMAC for authentication without other revocation methods would lead to a subsystem that is less secure.
@jnugh amazing, thanks for that detailed explanation 😄 cc @Dima Grossman @Zac Clifton