I am working on a website that requires some ajax calls in order to improve flexibility and performance. My ajax calls is for a ranking system. I need three input values to be processed with ajax (storeID, clientID, orderID). To submit an action with ajax, I want to make sure that the parameters values sent were not modified by users using web tools. So I was thinking of three different ways to guarantee that the information sent were not changed:
Send an extra value that is the encryption of all the data sent all together. So at the server side while processing ajax, I can re encrypt the data sent and see if the encryption result matches the encryption value sent.
Send all the data as one encrypted value. Then on the server while doing the ajax, I can decrypt the data and assign the values again.
Send only the orderID and its encryption then using method (1) verify that the orderID is not changed, and using the database query, fetch the two other information.
Here's my opinion on each of the three ways:
Consumes memory since I have to send orderID, clientID, storeID, encryptedID. Moreover, the information monitored in the ajax call will give people information about what happens when they rate an order.
I checked online for mcrypt_encrypt and mcrypt_decrypt but I've never used them. I saw that they produce a long string, but I prefer to keep my data sent short or look like the md5 encrypted data. Is there better methods ?
This is the elegant way, it looks straight forward but it needs some MySQL intervention, which could be time consuming especially when data grows in the future.
So which one do you think is better ? If you have more ways I appreciate if you share them here. Thank you
Example of scenario I want to avoid: Clicking a button will submit a form using AJAX by passing the Product ID. A user go to the source code, and change the ID of the product from X to Y. Now the user clicks the button and the form was submitted and the product of ID Y was be affected. As you can see, the parameter values sent are not secured and can be modified. I am searching for a way to guarantee that the parameter values sent are correct and not modified.
PS: This question is not about CSRF handling.
Everyone is trying to lead you to these points:
On the server....
And if you aren't doing 2 and 3, you're wasting your time completely on this idea. Whatever you come up with will only be adding obscurity to your insecurity.
If you want to use encryption, you may use the Mcrypt functions with the Rijndael cipher. That gives you a block of 128 bits to play with.
Suppose your three IDs (storeID, clientID, orderID) are 32 bit each, you can pack those together with a 4 character string to form a 128 bit block. The string will be used to check the decrypted data later on.
$block = pack('a4LLL', 'MyID', $storeID, $clientID, $orderID);
Then create a random IV and encrypt the block:
$mod = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
$iv = openssl_random_pseudo_bytes(mcrypt_enc_get_iv_size($mod));
$mySecretKey = 'LA72U/aLEOcDoN0rqtM5sehNNjd7TUSILiBgI8bej6o=';
mcrypt_generic_init($mod, base64_decode($mySecretKey), $iv);
$encrypted = mcrypt_generic($mod, $block);
mcrypt_generic_deinit($mod);
mcrypt_module_close($mod);
You'll need to encode the encrypted block and the IV before using them client side. Using base64 and swapping the / and + characters gives you a nice value that can be sent as a GET parameter:
$encodedBlock = substr(strtr(base64_encode($encrypted), '/+', '-_'), 0, -2);
$encodedIV = substr(strtr(base64_encode($iv), '/+', '-_'), 0, -2);
Later when those values are sent to your ajax scripts, just reverse the process:
$encrypted = base64_decode(strtr($_GET['block'], '-_', '/+') . '==');
$iv = base64_decode(strtr($_GET['iv'], '-_', '/+') . '==');
$mod = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init($mod, base64_decode($mySecretKey), $iv);
$block = mdecrypt_generic($mod, $encrypted);
mcrypt_generic_deinit($mod);
mcrypt_module_close($mod);
$data = unpack('a4str/Lstore/Lclient/Lorder', $block);
if ($data['str'] != 'MyID')
throw new Exception('Something fishy is going on');
If all goes well $data will contain $data['store'], $data['client'] and $data['order'].
You may also pack a nonce value into the block in order to protect against replay attacks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With