2

I'm looking into implementing an ownership check on JSON objects and want to avoid going back to the database to ensure ownership of said object/record (i.e., to prevent a user from updating an object/record they do not own - mostly CRUD operations). This would occur in the context of a web-application/service api.

My thought is to have a private server-side system assigned "ownership" v4 UUID tied to every user record, so that when passing any user owned JSON object to the view, the system encrypts the owner's private "ownership" UUID using bcrypt with a random salt and assigns it to the object/record (where it could be persisted along with the record for caching purposes so it does not have to be re-encrypted). Also, I should note it's possible that owned objects may be encrypted separately each with their it's own random generated salt, even though they are in fact the same user's ownership UUID (this is needed to help prevent tracking of user's object ownership in certain application use cases).

Later, if a user tries to update said object, the server would have to validate their private UUID against the bcrypt hash to ensure if they have the ownership rights to update the record.

This is assuming that I would encrypt using an appropriate number of rounds for the encryption. Another assumption I'm making is the encryption and checking time would outweighs any database check times. The last assumption to point out is this strictly an app security check and would do nothing if someone actually got a hold of the database.

My current thinking is that with the UUID being random and it's large string size (along with an appropriate number of rounds) would make having these bcrypt hashes exposed publicly not be so much of a problem. Or is this approach just too much risk/oversight?

2 Answers 2

3

You don't need bcrypt here.

Bcrypt and other similar password hashing functions use salts and iterations in order to cope with the inherent weakness of passwords, which is their vulnerability to exhaustive search. The space of possible passwords, the one which most users will choose and be able to remember, is simply too small for comfort. We use iterations so that the attacker's task is slowed down. We use salts so that the attacker may not make economies of scale when trying to break several passwords. But all of this makes sense only because breaking one password is feasible.

When the data which is to be hashed (for ulterior verification) is a strong random key, chosen uniformly from a space large enough to defeat exhaustive search, then salts and slow hashing are not necessary. This is the case for your "private UUID". A "v4" UUID is supposed to contain 122 bits generated from a cryptographically strong PRNG. This is way beyond that which is amenable to exhaustive search. This "private UUID" is a key in the true sense of the term.

So, in a given protocol where you hash these "private UUID" with bcrypt, you can replace bcrypt with a simple hash function (e.g. SHA-256) and forget about the salts. In your case, the server stores h(UUID) for some hash function h, linked to a user, and the user has to show the UUID itself to be granted access. This is the simple "password" model but with a really strong password, which does not require the tools developed to tolerate human-remembered passwords (which are not strong). Of course you would want to run the whole protocol under the protection of some layer which ensures that the client talks to the right server, and the transfers are protected from eavesdropping and alterations (basically, SSL).

2
  • Thanks makes sense, this is exactly what I'm looking for. I had an inkling that I was over-engineering and/or underestimating UUIDs, but I wanted to be on the safe side. The only thing I would dispute is the not salting part. One of the requirements is that users could be anonymous in certain parts of the application, and by not salting the UUID for hashing it would result in a hash that could be identifiable between JSON objects. Granted, it probably would be difficult and time consuming for an attacker to do this but the hashes would still be traceable without salts.
    – Jordan
    Commented Oct 15, 2013 at 14:01
  • The inherent weakness is UUIDs aren't guaranteed to be generated by a crypto-RNG but a (strong) ordinary RNG. There's a story they were once generated by hashing V1 UUIDs. Whether or not the story is true it illustrates the point. UUID != CRNG.
    – Joshua
    Commented Nov 26, 2016 at 17:56
0

One other approach is to sign the secure fields using HMAC.

{"RecordID": "nnn", "Day": "day_since_epoch", "OwnerUserId":"[email protected]", "OwnerUserIdHmac":"{yyy}",...}

Where yyy = HMAC($RecordID + $OwnerUserId + $Day, $SecretKey[$Day])

Secret key is rotated daily and you can decrypt using an old day's key.

You must log in to answer this question.

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