Budhaditya Biswas Budhaditya Biswas - 1 year ago 40
PHP Question

Prevent user from manipulating query string parameter

Situation: Unregistered user visits website and issues a request for an item. As per the current data flow, this request gets inserted in db first and the request id is carried over in the url of the subsequent pages henceforth( where user gets to add in further info).

Problem: User can change the id.

What i have done so far: As soon as i retrieve the id after request is inserted by using lastInsertId(), i store it inside a session variable and check in the subsequent pages against the id from $_GET. I also implemented CRSF protection but when the token matches, session token is unset. Hence even if the user refreshes on the same url, the check fails.

How do i solve this problem?Please point out the concepts that i am lacking. Also when many concurrent users will issue requests, the server determines which id is for which user from it's unique session id which will be different for different users, correct?Can there be any problems or vulnerabilities due to this concurrency?

Answer Source

Based on the line '( where user gets to add in further info)' I assume you're using some kind of form / POST to get data across? I would use the technique stated in AtulBhatS comment and use hashed data in. You could either set hashed data in the GET or set it in a hidden field in the before mentioned form / POST field.

Basically it's something like this:

$id = $thisRequestIdOfYours;
$hash = hash('sha512', 'aRandomSaltStringOnlyKnownByYourScript'.$id);

Just use these 2 values as a $_GET (instead of only the $id, like you do now). Or set it in a hidden field.

Upon resending of the post you could do a check:

// Use $_POST if you use the hidden field way.
if( hash(sha512, 'aRandomSaltStringOnlyKnownByYourScript'.$_GET['id']) !== $_GET['superSecretHash']) {
    // h4x0r d3tect3d
    die('you have no business here');

Because of the 'salt' (aRandomSaltStringOnlyKnownByYourScript) which is only known inside your script it's very very hard to decode and alter the get with the hash to match the manually changed ID.

Obviously like with all passes, the stronger the salt, the harder the crack. So throw in some whitespaces, numeric, or even other characters to catch the bad guys.