views:

214

answers:

4

Although I always check that someone is allowed to access a record, I normally use a UID in query strings as I feel it discourages the temptation to "poke around" that ?id=1, ?id=2 does.

I find though that it makes it a bit convoluted to do lookups across multiple tables as you need to store the UID as well instead of just the record id.

If I was to pass an encrypted string of the id number through the query string and then decrypt it to do a database query would this add massive overhead?

This would mean I can just work with the primary key (though I would still obviously check that they have permission to view the record) and could make unique links each session (or change anytime throughout a session) - which would be useful if there's a lot of AJAX driven content you don't want them trying to play with.

Is this a really bad idea?

A: 

Why not just base64encode/decode the IDs? If you're only doing this to prevent legitimate users from experimenting with toys they do in fact have permission to play with anyhow, there is really no purpose in doing anything particularly fancy to discourage them.

Brian
To put it in context - if I'm developing a game, people will always try to "game" the system. If there is inventory in a shop, they might bookmark the id/uid of an item in that virtual shop and look at it later by accessing it directly. Sure this is legit and I can't stop that, but if the link is unique every session or half hour even and unique to that user then it stops the poking around.
niggles
Who cares if the user is able to find random items in the virtual shop? Why is this a problem?
Brian
I would prefer 1 time links for everything to avoid bookmarking of links or the possibility of players send other players links.
niggles
+1  A: 

You should definitely check for permissions on every request. You should never rely on just input data for security!

And remember if you can decrypt it, so can the malicious user who wants to hack in your site.

Using a session to store permissions is a trade off security in favor of performance and I think it would be average security to do it.

But still - if you have sensitive data - check on every request, every time. Don't optimize for few microseconds in the name of less security.


As now I saw your real problem in a comment, I can suggest using some sort of additional hash for every refresh the user makes and save it in the session of the user. Then check if the user uses the same hash e.g.:

$hash = md5(microtime());
$_SESSION['secret_user_hash'] = $hash;

And put it in URLS like:

&z=<?php echo substr($hash, 5, 10); ?>

And after a user makes the request just check if it is the same hash.

Keep in mind that if you are using heavy AJAX you should always update your hash, when you change it in the session. The best way i can think of is keeping an array in the session of random hashesh(e.g. 5) and use them on random for the query. So you have a bigger pool and you don't have to update after every request.

bisko
The functions would still check permissions and it's not really sensitive data, it's just an idea for make a unique link every time without refactoring the database or changing anything. I guess i can test how long it takes to do a bunch of encryption / decryption queries as opposed to straight uid and see if this would impact in a heavy use situation i.e 5000 simultaneous users etc.
niggles
"I can suggest using some sort of additional hash for every refresh the user makes and save it in the session of the user. Then check if the user uses the same hash" -> that would work to stop them bookmarking it and is less overhead that decrypting the string for each and every query -> and it would still allow me to refresh the hashes every X minutes so they can't come back to it later.
niggles
The encrypting and decrypting are not as expensive as database usage, so your main load would be on the database. Don't worry about the encryption. Just don't make it too complicated... As for the hashesh - keep in mind that there could be some users that just leave their game window open for a long time and this can change their hash. You can try to send some regular requests to keep the session alive and not to change the hashes.
bisko
I don't understand why encryption of ids is needed at all. If you use session data to power transitions between pages, there won't be any means to use bookmarks regardless.
Brian
A: 

Make your UID a hash and pass that through.

Unless you don't want to refactor your entire schema and codebase, then rot13 / base64 encode it.

Josh Lindsey
A: 

why would it have any bearing on how you access your data, access and display are two separate entities. your key should be used in a query but you never need display it if you dont want to. you can hash it, you can mod rewrite so it never is visible in the url...there are many options while still querying key in you tables. you can even generate it on the fly for display if you set a pattern. P+IDHASH+ANATTRIBUTE or something. using a base64 on an integer and decoding to run your query will not cost you anything more than milisecond or so. remember you aren't hashing in your queries so they will remain the same you will encode/decode one item which is not an issue with time

Matt
This is basically how I've started implementing it with MCRYPT_RIJNDAEL_256 and base64 encoding + mod_rewrite so I end up with something like:/bank/create_account/91xqJttvM61PH|9d+ahAeDtrZ2apBna8Yhz83deROZg=which will query bank of id=1 to create an account for the user. A transaction between the bank would be something like/bank/transaction/91xqJttvM61PH|9d+ahAeDtrZ2apBna8Yhz83deROZg=/LemOfavO6jNi1yZQbYgE0J|MtLSyVePMkgauJPLTWxI=sending $x to that bank.It seems to work fine - and you're right, it's only a tiny bit of overhead.
niggles