Since the initial launch of RATTS, I've been contemplating on the security implications associated with the use of JWT. For context, this has been pivotal in implementing stateless authentication and deferred user registration but while JWT solves one important problem, it introduces another: the leak of potentially sensitive token payload.
This article revisits the JWT premises, its grey areas and focuses on alternatives. In case you're missing the bigger picture, do check-out the RATTS article first.
To reiterate, the JSON Web Token (JWT) is a standard for passing claims between systems, usually packed with JSON Web Signature (JWS) to guarantee data integrity and for compact, URL-safe serialization. However, the claims are passed unencrypted, in base64-encoded form, exposing the data within.
This can be an issue in most use cases but for the remainder of this article I will address the JWT uses in this application.
involves generating a token on user login and passing it to the front-end application, running on the client machine. It is afterwards subsequently passed back to the server with every API request involving user-related operations. In order to keep the authentication mechanism stateless, the token claims need to include the authenticated user's identifier. This enables the backend to perform the correct database queries on behalf of the user. This means that once logged-in, one can potentially decode and read their associated database record ID. They could find they're the N-th user of the application, since it is obvious that the ID is auto-incrementally allocated. The temptation would then be to forge tokens with N+m as ID. Surely, the SHA-2 signature is sufficient to prevent such attempts but there may be yet unforeseen cases when the user's knowledge of own ID could become a problem.
also needs a token but this time containing the email of the new user. Now, there's not such a big deal if the users sees one's own email address but remember that emails pass through multiple network nodes and mail servers, before being stored on third-party servers.
For these reasons, it is preferable to encrypt the claim at the cost of a some additional computational overhead per API request. Thankfully, there's a standard for that too: JSON Web Encryption (JWE).
One crate I found to be following the JWE standard specifications to the letter and that is biscuit
. The API is well documented and flexible enough to allow in-dept customization, should it ever be needed. The crate has support for JWT and JWS as well and that prompted me to drop the dependency on jsonwebtoken
crate in its favor.
As of now, the tokens generated by RATTS are signed with HMAC SHA-256 and encrypted with AES-256 GCM. A random nonce is generated at each encryption such that the ciphertext differs even when the plaintext doesn't change. This setup is a generally accepted tradeoff between security and performance.