Preventing user tampering through changing data values in PHP/AJAX - php

I have several forms where a user can make changes to events tied to their account but I'm not sure how to take care of security involving the user changing the value set in data-employeeID for example.
I initially set up a security check script that would look at an identifying piece of data coming in through ajax requests and before it goes on to actually use it. It would first do a series of mysql joins to work it's way back to the Users table and then do a final check to make sure the ID_NO of the users table can bej oined using the session stored userID.
I assume this would work and be secure. But the site is rather large, and often times 5 or 6 values are being passed though ajax calls. So on every public facing function I would need to repeat the process for each variable (Unless they can be tied together along the way; not always possible) before continuing on.
After googling around though I've only found results related to php/ajax processing errors, or security surrounding the user who is making the request.
If the user is legit though they can still make changes on the page, and keep all of the correct information except for changing something like the meeting ID to something else. If I only check the users CompanyID, or DepartmentID though my callback chain and skip meeting ID they will be able to get data inserted into the database that is not accurate, with a meeting possibly being manipulated because I didn't create a callback chain for every single variable being passed between ajax and PHP.
I feel there must be a better way and that this is a solved problem so I'm hoping someone can point me in the right direction before I dive too deeply into making an over-complicated process. Thanks.
Requested Sample Code:
$.ajax({
type: "POST",
url: "<?php echo base_url().'meetings/addstarttime/'?>",
data: {
validDaysID: this.dataset.validdaysid,
departmentID: this.dataset.departmentID,
companyID: this.dataset.companyID,
employees: employeesArray,
start: this.dataset.start
},
success: function(data){
//update html to show updated values
$validDaysID = $_POST['validDaysID'];//unencoded
$securityArray[] = array("validDays", $validDaysID)//Check if access to this value is OK
$tieItBack[] = array("Buildings", "BuildingID");
$tieItBack[] = array("Location", "LocationID");
$tieItBack[] = array("Department", "DepartmentID");
$tieItBack[] = array("Companies", "CompanyID");
From there I make a query that selects the COUNT(*) of rows for the initially requested table, validDays, INNER JOINS the tables specified in the tieItBack chain and then finally checks if Companies.ID_NO == $this->session->userdata('CompanyID');
If there is a hit then they have access, if there is no rows then they do not.
For this example three of the variables can be knocked off in a single query but that is not always the case. Also this is using replaced table/col names cause I'm paranoid I guess but the structure is the same.

You have no reliable way of guaranteeing that the client-side code is doing what you want it to do.
Your server-side software should distrust all input, regardless of whatever client-side validation you've already written. (Users might not even run JavaScript, for example.)
This isn't a problem that can magically be solved. It's just a reality about networked computers and software development.

Related

PHP setting var to only a portion of a string

I have a panel I'm making that will use session data from another forum to give it permissions. Basically when the user logs into our forum and the session and trust is created on the forum, they can click on the panel and the panel will check their browser cookie for the session id and trust id. It then takes that trust id and checks the forum's database for the user id associated with that trust. Then takes the session id and verifies that it belongs to that user id. The issue is that when I get the session id, the associated user id is part of a blob that i have to cast in order to get the data from the field. So I get a result like this:
('7c64c90413beb7d139c64ccc8b13380b',
'a:12:{s:12:"sessionStart";i:1454075264;s:2:"ip";s:4:"b???";s:11:"sessionCsrf";s:16:"-2Yx13nBLdstUj4H";
s:7:"user_id";i:20;
s:13:"password_date";i:1453353041;s:16:"previousActivity";i:1454072099;s:13:"trophyChecked";b:1;s:16:"promotionChecked";b:1;s:16:"dismissedNotices";a:0:{}s:15:"lastNoticeReset";i:0;s:13:"canAdminUsers";b:1;s:20:"userModerationCounts";a:2:{s:5:"total";i:0;s:13:"lastBuildDate";i:1454075264;}}'),
I know there is a lot there, but I singled out the part that matters to me. The first column returned is the session id, which im using to verify the user id, but the user id is in the middle of that all that crap in the second column. So you can see where I single out the definition, what I want to do is just assign that "20" after "user_id;i:" to a variable and discard the rest. I'm sure this is simply done, but at this point I think I'm just nuking it out and spinning wheels. I was thinking explode, but the structure of that data seems like that's not an option.
That data is simply the result of a PHP serialize() call. You can pass it to unserialize(), which will provide you with an array containing the values.
<?php
$str = 'a:12:{s:12:"sessionStart"…etc…etc…i:1454075264;}}';
$arr = unserialize($str);
var_dump($arr['user_id']);
In case you’re trying to extract the value from within MySQL alone, for some reason I’ve done something similar with an awful query containing lots of nested SUBSTR() and LOCATE() just two weeks ago. I wouldn’t recommend it. Especially because in my case I was doing a one-off reporting query, while you’re trying to do authentication with it. People might try to use specially crafted cookies to circumvent your string extraction and gain illegitimate access.

Procedure for restricting user from typing in php url

I've got a database where you can load details of a candidate through the following get request url: database/candidates/?loadcandidate=n where n is the id of the candidate to load.
Is there a common practice where you can add something to the get request which would prevent my users from being able to type in any id to access the details of candidates? I want them to only be able to access the candidate page from my search results or by bookmarking the candidate page and revisiting it later.
I could probably figure out my own eccentric way of doing this, but I'm wondering if there is a common procedure?
Get requests are get requests and you can't prevent users from changing get request variables.
But reading between the lines, I think the solution you're looking for is obfuscating (hiding/cloaking the intended meaning of) the userid so that it can't just be plainly accessible via changing the id incrementally, (e.g., ?loadcandidate=1/2/3/4/5/6...).
In this case, try assigning a user code so that it would be harder to pull up candidates just by guessing the ID.
Just as a simple example (which by no means should be used for production) try simple MD5 hashing and get the first 6 digit substring.
Example:
1 = c4ca42
2 = c81e72
3 = eccbc8
...
database/candidates/?loadcandidate=c4ca42 will pull up candidate with user id = 1.
So that when you access database/candidates/?loadcandidate=n, n will be something much more difficult to guess, thereby decreasing the number of random lookups exponentially. Of course this will all depend on how random the obfuscation/code actually is.
Hope this helps!

checking whether a form value has changed upon submit

I'm creating a web app with Codeigniter, and I've created some edit forms (which pull current values from a mysql database). The user can edit the current database data by editing the data in the form.
What I want to do is perform certain actions if the user changes certain values. So, I don't just want to perform the action when a field has a certain value, but only at the point when the user changes the value and submits the form. (Specifically, when the user indicates that she's performed a certain task by changing a value from "no" to "yes", then I want to do things like set a timestamp for the completion of the task, etc.)
I've tried googling a solution, but I'm having trouble finding what I need. Can anyone point me in the right direction?
I haven't used CodeIgniter, but I've certainly done what you're doing in pure PHP-based sites.
I've followed two ways of thinking, in different projects.
Strategy #1: Multiple writes are cheap.
If a user clicks "Submit" rather than "Cancel", they've changed at least one field. So the cost of doing an UPDATE table SET name=%s,email=%s,gender=%s WHERE id=%d isn't much more than a simple UPDATE table SET gender=%s WHERE id=%d. If you're going to the expense of a WHERE and a write, making the write a few extra fields doesn't matter, especially with the frequency that it'll happen.
So: don't worry about it, just update everything with what you get back in the form. If you overwrite a field with the same data, it doesn't matter. When it comes down to it, you want your database to reflect everything that came back in the form, regardless of what was in the db before.
Strategy #2: Use a session variable.
If you've populated the form with current data, you've already likely pulled it into an array. So copy the array into $_SESSION, and compare the fields after the POST.
Strategy 1 is easier to program, but does use slightly more database CPU and bandwidth. Strategy 2 is has slightly less database impact at the expense of quite a bit more CPU used on your web server, and it's more prone to development error.
I still don't know which way is better, but the arguments for both seem valid. These days, I tend to go for whatever solution is the most simple. But I realize that it's easier to scale your web cluster than your database cluster, so if you're developing something that will be very large, it's probably better to put more effort into optimizing things in favour of your database rather than your web servers.
Note that if you're storing your session data in a database instead of temp files, then #2 is actually more costly in terms of database server impact.
You're saying that the users can edit entries from a database, so just send the record id as a hidden input field.
By the time the user submits the form, you retrieve the database record using the hidden field and make the necessary comparisons.
Btw, to prevent users from trying to modify other's records it's advisable to add a checksum to the id field that only you can verify, something that can be done using hash_hmac. Alternatively, you could verify the record ownership if they're logged in.
The only real solution here is knowing the initial value of the form input and then comparing it to the submitted value. You could pass the original value to the browser as a hidden form field and a slightly different name and then compare the two server-side though -- that should net you the desired effect if you don't know what the original value is already.

how to prevent two separate ajax calls in php from modifying the same database

I got a javascript client that sometimes sends two ajax requests within milliseconds of each other to the (php) server. (it's a javascript bug that I have no control over from the client side, i only got control over the server side).
The first request checks if a voucher already exists in the dbase (given a couple of parameters.. ie cust id etc).. if the voucher already exists, it just re-uses the voucher and updates is value, if it doesn't , it creates a new one from scratch.
the problem is that before it has finished checking if the voucher exists.. the second request comes in and checks if the voucher exists as well.. at that point the first hasn't created the voucher yet..
so long story short.. we end up with 2 duplicate vouchers.. (and the dbase doesn't restrict the voucher name to be unique. I have no control over the dbase either)..
so how do I prevent the second ajax request from doing anything until the first has done it's thing?
Keep in mind that the two requests are two different threads.. so if I make any $isVoucherCreationInProgress variables, it would be useless as the second call would be completely oblivious about it.
ideas?
If the 2 ajax requests are from the same client, on the server side make a lock-like system, so if someone has checked for a voucher existence, set a session variable until it finishes what it has to do. So when the second line comes it first checks for the session and if ( someone else is using the voucher ) finish it with a message check later, so on the client side when it comes with a denied message you can simply send it with a 1 second delay, to be sure nobody is "working".
Hope this helps.
Or you could see this question in order to make a mutex in php: PHP mutual exclusion (mutex)
Personally I would think of a very simple method. On your server, you must have a procedure where you will create the voucher. Keep a global array and just before creating the voucher, set the index of array as the id, something just like key = > Value, where key may be the id of the voucher and Value may be a status such as "creating". After creating the voucher, you can remove the entry using the id of the voucher as the key.
Now, every time just before creating the voucher, simply check from the global array of the key already exist, if yes and Value="creating", then in fact, you are actually creating the voucher, so then you exits
Hope it helps, :-)
Use transactions. If you really can't touch the database (not even make your own statements), you can use STM or the like. Wouldn't be too hard with locks either, but either way requires that your application is running continuously. You can run a server with software like phpdaemon and forward a specific path to that server, to get that continuance.
I understand that you create a new row in one table of your database.
You should add a unicity constraint so that you can't add it twice. Is it possible that you have to create several vouchers? Could you give more info on this?
Regarding the update, you should add a 'version' field to your row. The client side needs to have the correct version number to update the row. Thus it avoids a problem of unwanted concurrent update. This is a best practice with ORM, you may check this looking for 'optimistic update'.
As you have no control on the db, create a cache of requests (i.e. static object) in your server and create/update a row if nothing (regarding this customer + others parameters if needed) in your cache (like this one for example http://www.php.net/manual/en/book.memcache.php) . Your cache should clean itself atfer a while (I guess there are cache solutions in php).
Another idea (ugly but because it seems you are so limited with solutions): just make it slower. Wait sufficiently to make sure there is noone else (you will need a loop which checks and undo if needed - with random for convergence).
You can either set a flag (in JavaScript) when your ajax request starts - check to see if it's set then RETURN, or you can change your AJAX request to synchronous.

PHP - Is this a good method to prevent re-submission?

This is related to preventing webform resubmission, however this time the context is a web-based RPG. After the player defeats a monster, it would drop an item. So I would want to prevent the user from hitting the back button, or keep refreshing, to 'dupe' the item-drop.
As item drop is frequent, using a DB to store a unique 'drop-transaction-id' seems infeasible to me. I am entertaining an idea below:
For each combat, creating an unique value based on the current date-time, user's id and store it into DB and session. It is possible that given a userid, you can fetch the value back
If the value from session exists in the DB, then the 'combat' is valid and allow the user to access all pages relevant to combat. If it does not exist in DB, then a new combat state is started
When combat is over, the unique value is cleared from DB.
Values which is 30mins old in the DB are purged.
Any opinions, improvements, or pitfalls to this method are welcomed
This question is very subjective, there's things you can do or can not do, depending on the already existing data / framework around it.
The solution you've provided should work, but it depends on the unique combat/loot/user data you have available.
I take it this is what you think is best? It's what I think is best :)
Get the userID, along with a unique piece of data from that fight. Something like combat start time, combat end time, etc
Store it in a Database, or what ever storage system you have
Once you collect the loot, delete that record
That way if the that userID, and that unique fight data exists, they haven't got their loot.
And you are right; tracking each piece of loot is too much, you're better off temporarily storing the data.
Seems like a reasonable approach. I assume you're storing the fact that the player is in combat somewhere anyway. Otherwise, they can just close their browser if they want to avoid a fight?
The combat ending and loot dropping should be treated as an atomary operation. If there is no fight, there can't be any dropping loot.
That depends on your game design: Do you go more in the direction of roguelikes where only turns count, and therefore long pauses in between moves are definitely possible (like consulting other people via chatroom, note: in NetHack that is not considered cheating)? Can users only save their games on certain points or at any place? That makes a huge difference in the design, e.g. making way for exploits similar to the one Thorarin mentions.
If your game goes the traditional roguelike route of only one save, turn basement and permadeath, then it would be possible to save the number of the current turn for any given character along with any game related information (inventory, maps, enemies and their state), and then check against that at any action of the player, therefore to prevent playing the turn twice.
Alternatively you could bundle everything up in client side javascript, so that even if they did resubmit the form it would generate an entirely new combat/treasure encounter.

Categories