Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,026 | Comments: 44,842

filter by tags archive

Hiding values, API keys and other fun stuff

time to read 3 min | 537 words

This post is mostly about fun ideas. In one scenario, we had the need to show data to the user, but there was some concern with regards to the hackability of the URL.

In general, you should be handle such things within your code, checking permissions, etc. But I decided to see if I can do something nice with things, and I got this:

private static object HideValues(string entityId, string tenantId, byte[] key, byte[] iv)
    using (var rijndael = Rijndael.Create())
        rijndael.Key = key;
        rijndael.IV = iv;
        var memoryStream = new MemoryStream();
        using (var cryptoStream = new CryptoStream(memoryStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write))
        using (var binaryWriter = new BinaryWriter(cryptoStream))

        var bytes = memoryStream.ToArray();
        var sb = new StringBuilder();
        for (int index = 0; index < bytes.Length; index++)
            var b = bytes[index];
            if (index % (bytes.Length/4) == 0 && index > 0)
        return sb;

This will generate a “guid looking” value that we can send to the user. When they send it back to us, we can decrypt it and figure out what is actually going on in there.

Because it is encrypted, we know that this is a valid key, because otherwise we wouldn’t be able to decrypt it to valid data.

Passing 15 and 32 as the first two values, I got the following value back: 2A8AC8888-46B92092-BFD81393-7A6FB1

And it handle larger values as easily, of course. Quite fun, even if I say so myself. Not sure if this is useful, but I got into writing code because it is a great hobby.


John Downey

Be very careful about encrypting data without providing any integrity protection. If you don't integrity protect the encrypted value, with an HMAC signature for example, then attackers can intelligently modify the encrypted value and look at indicators (error codes, timing, etc) to leak the input plaintext. This is the same problem which led to the padding oracle issue found in ASP.NET and other frameworks a few years back.

Ayende Rahien

John, How would you use HMAC to secure things in this case?


Maybe it is more secure to create a random url for each shared resource.

Ayende Rahien

Andres, This is security by obscurity, you can't decide to remove one particular value, etc.

The Thing

I think if you saw this in someone else's could we would be treated to a long blog post detailing all the things wrong with it.

Ayende Rahien

The Thing, One of the reason that I am posting this is to GET your feedback. Feel free to post about all the things broken with it.


Andres, This is security by obscurity, you can't decide to remove one particular value, etc.

I am not sure that you have understand me, I have being talking about to store in a database a relation of entityId and tenantId with a totally random guid, for example 15 and 32 with 280b7c8b-e590-4671-8c69-ef25955eaa3f.

I know that it requires more logic and it is not as functional as your design, but it is totally unbreakable and you have a great granularity if you want to allow, disallow or change one single resource access.

Thomas Krause

As John mentioned, you didn't include any kind of integrity check in your code. The question is: Do you want to hide the entity ID and tenant ID from the user or do you want to just prevent tampering with them?

In the second case you can use a standard HMAC mechanism (compute checksum and encrypt this checksum). In the first case you can do the same and then encrypt the message as a whole again like in your code.

Another problem of this approach is that it's prone to message repeat attacks. Once an attacker knows, that a specific tenant+entity id results in string X, he can always send this string X (think man in the middle attack).

So it would be nice to add a changing value to the mix which you can also check.


I actually did this once myself, redirecting users from non-secure product page to a secured order page on another domain, in another application (long story short: keeping cert payment to the bare minimum).

This is a much better solution than saving session states in a database, and it makes sure the redirect never expires (a good thing for us), but I never liked that solution. Maybe because this is basically an ASP.NET WebForms ViewState.

And you want to salt this.


I think you can't tell if the data sent is actually valid because any 16 byte value should decrypt to some (random) plaintext. A cipher is just a permutation of all possible 16 byte values. People could make your app believe that there was some tenant with id "65&/$%bnsdjg" for example.

Replay attack possible here. No way to revoke a guid once handed out. Can be stolen.

John Downey

The easiest thing would be to run the encrypted data through HMACSHA1 with a different key than the one used for encryption. You would then append that to the data being sent to the user. In C# it would look something like:

byte[] signature = new HMACSHA1(key).ComputeHash(data);

When the user returns be sure to validate the MAC first and reject any ciphertext that is not properly signed before ever attempting to decrypt it. You should also be aware that == will likely leak timing information during MAC verification[1].

[1] http://codahale.com/a-lesson-in-timing-attacks/

Guy Mahieu

We actually use this same principle to avoid ppl tampering with urls containing details about a payment. We decided to use cipher block chaining as well to patterns in the URLs for similar parameters.

Guy Mahieu

Sorry, I looked over the init vectors part of your code before when I wrote my CBC remark... our solution generates new IV's for each call and passes them as part of the url.

Ryan Heath

We used a certain method to protect our image servers. We previously had build an url scheme that could specify width,height,dpi of uploaded images. Then we found out it was being abused and our servers were dying. The problem disappeared as soon as we had implemented this kind of protection. It was fun, yes :), but I would not use it for really sensitive information, though.

// Ryan

Gabriel Vince

Hi, indeed integrity is missing - a good example are authorized links for Amazon S3, it let you access content with known ID (uri), but there is expiration infromation (a unique nonce will do it too) and HMAC-SHA1 signed String containing a secret key, nonce and the ID.. But you are right, sometimes better than storing everything to server side session. And thank you - a very nice example for inspiration.

Comment preview

Comments have been closed on this topic.


No future posts left, oh my!


  1. Technical observations from my wife (3):
    13 Nov 2015 - Production issues
  2. Production postmortem (13):
    13 Nov 2015 - The case of the “it is slow on that machine (only)”
  3. Speaking (5):
    09 Nov 2015 - Community talk in Kiev, Ukraine–What does it take to be a good developer
  4. Find the bug (5):
    11 Sep 2015 - The concurrent memory buster
  5. Buffer allocation strategies (3):
    09 Sep 2015 - Bad usage patterns
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats