To clarify the question, here's our case:

We generate encrypted tokens by applying AES-CBC (256 bit) and Base64 to payload:

encrypted_token = Base64.encode(AES_CBC_256.encrypt(key, iv, payload)).

These encrypted tokens are publicly available. It's quite obvious that these tokens are Base64'd, so that's not a secret. Our web service provides an HTTP endpoint which receives encrypted token, decrypts it (via AES_CBC_256.decrypt(Base64.decode(encrypted_token)) and performs some action with it.

Decryption function implementation (let's name it decrypt_token) does some stdlib OpenSSL and Base64 invocations. Normally the endpoints responds with HTTP 200 OK. We capture all the exceptions we are aware about and respond with some specific HTTP code (say, 400 Bad Request). But unexpected exceptions might still occur (say, if someone adds some bugs to decrypt_token or in case of OpenSSL dependency update). These exceptions will lead to HTTP 500. To sum up, the endpoint might respond with 200 (in case of valid token), 400 or 500. Note that there are no any additional error details in response body or headers.

Finally, the question: is it possible for an attacker to obtain some information of tokens structure due to response codes variation? Are there any possible vector attacks? One possible enhancement is to handle all the exceptions and always responds with the same error code. Is it necessary? Are there any known related security incidents?



1 Answer 1


An immediate security concern that comes to mind is that you seem to be using CBC without authentication. This is a dangerous practice (see 1, 2, 3) due to CBC's malleability. In short, encryption alone gives you only confidentiality, but no integrity protection: Anyone can still meddle with your ciphertexts, which can result in many surprising problems. For example, if your plaintexts exceed AES block size (16 bytes), your encryption scheme most likely uses some sort of padding. Any tiny difference in the padding validation enables an attacker to perform a padding oracle attack on your scheme. It is critical that your implementation does not reveal whether the padding was correct or not. However, in practice the recommendation is to perform an explicit integrity check before any AES-CBC decryptions happen (encrypt-then-MAC). This avoids the issue altogether, altough it doesn't prevent all attacks.

Cryptographic integrity of your ciphertexts can be asserted via different means. An older, traditional setup, is to use a Message Authentication Code (MAC) on your ciphertexts (as mentioned above). A more modern approach is to utilize Authenticated Encryption, which combines encryption and authentication in a single scheme - you don't have to care about it anymore.

As for your question about the varying responses: This is hard to tell, given the limited information available. A varying response of any kind, be it message contents, response codes, timing differences might enable an attack. For CBC, the most common would be the already mentioned padding oracle attacks, but other types of oracle are also possible: This is all highly dependent on your exact protocol and how it behaves when it encounters modified ciphertexts.

To avoid many of the pitfalls others have fallen into, you should avoid rolling your own crypto as much as possible. For example, the NaCl secretbox is suitable for storing encrypted tokens, or JSON Web Encryption, GPG/PGP, or age*. All of these have considered a multitude of potential side channel attacks, authentication, DoS attacks and more.

*Note that the latter two use asymmetric cryptography, where anyone can encrypt messages (but not decrypt). You may need to adjust your protocols if you switch to asymmetric cryptography for your tokens, so that only you can generate them.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .