PHP - Prevent client from tampering the ID of a form - php

How to fix the security flow of this code:
<a href="http://localhost/mypay/admin/company/#"
data-pk="26" data-url="http://localhost/mypay/admin/company/update/profile"
id="name"
name="name"
data-type="text"
data-source="">dfg</a>
This uses x-editable [bootstrap] - http://vitalets.github.io/x-editable/
I am just curious how to improve my security for my application if ever the client changes the "PK" primary key of the data. Where should the ID must be placed or what other security measures I would create to prevent them in doing it?
I use: Bootstrap and Codeigniter.

You'll have to check on the server side if the current user is allowed to edit this entry. Do not try to secure the client side, it is impossible. People will always be able to edit data on their computer, it is your responsibility to control it when it arrives at a place you control.

We, PHP coders, don't always see that weakness in our code. We do a big fuss about identifying the users (pw, sessions, etc.) and we clean up the code to prevent SQL injection of all sort. OK ! But what if a perfectly identified user, who is legitimate to update HIS OWN record (say he's ID 24) just send back his update form to your app with all empty fields and ID=23, then ID=22, etc.
One could easily wipe out all your records in a few minutes (even faster with a little loop: for(id=1, id < 10000, etc.)
So, very good question INDEED !
Here is my solution (certainly not the best one):
When an identified user click on a button to edit HIS record, I do this:
I read his record (SELECT) to get the data.
I UPDATE that record putting two temporary informations in it: a timestamp and a random string (a 35 characters long string, like an MD5 but randomly created).
Then I send to that user an edit form with all data, including a hidden field {name="id" value="24"} and another hidden field {name"UpdatableOnlyBy" value="ks3kms36di7eur94k3n..."}
Whenever a form comes back by $_POST[] to update a record, say this #24, I accept to do it ONLY IF the {UpdatableOnlyBy} string equals the one temporarily stored in that record AND if the timestamp is not older than 20 minutes. Then, and only then, I do the UPDATE (which by the way sets that special {UpdatableOnlyBy} field back to Null).
Any data coming in FOR ANOTHER ID will not lead to any UPDATE, because the records aimed at do not have the same random {UpdatableOnlyBy} string.
I leave up to you to decide when and how to clean those two fields, if they are left with
old MD5-strings and timestamps. For my part, I have a cronjob at 0h25 that clears all those fields for yesterday and before. But in the past, I have kept those data to see how many records pulled for being updated where left "orphans" (edit forms who never came back...). In one of my app, it was less than 6 %.

Related

What do you think of this approach for logging changes in mysql and have some kind of audit trail

I've been reading through several topics now and did some research about logging changes to a mysql table. First let me explain my situation:
I've a ticket system with a table: 'ticket'
As of now I've created triggers which will enter a duplicate entry in my table: 'ticket_history' which has "action" "user" and "timestamp" as additional columns. After some weeks and testing I'm somewhat not happy with that build since every change is creating a full copy of my row in the history table. I do understand that disk space is cheap and I should not worry about it but in order to retrieve some kind of log or nice looking history for the user is painful, at least for me. Also with the trigger I've written I get a new row in the history even if there is no change. But this is just a design flaw of my trigger!
Here my trigger:
BEFORE UPDATE ON ticket FOR EACH ROW
BEGIN
INSERT INTO ticket_history
SET
idticket = NEW.idticket,
time_arrival = NEW.time_arrival,
idticket_status = NEW.idticket_status,
tmp_user = NEW.tmp_user,
action = 'update',
timestamp = NOW();
END
My new approach in order to avoid having triggers
After spening some time on this topic I came up with an approach I would like to discuss and implement. But first I would have some questions about that:
My idea is to create a new table:
id sql_fwd sql_bwd keys values user timestamp
-------------------------------------------------------------------------
1 UPDATE... UPDATE... status 5 14 12345678
2 UPDATE... UPDATE... status 4 7 12345678
The flow would look like this in my mind:
At first I would select something or more from the DB:
SELECT keys FROM ticket;
Then I display the data in 2 input fields:
<input name="key" value="value" />
<input type="hidden" name="key" value="value" />
Hit submit and give it to my function:
I would start with a SELECT again: SELECT * FROM ticket;
and make sure that the hidden input field == the value from the latest select. If so I can proceed and know that no other user has changed something in the meanwhile. If the hidden field does not match I bring the user back to the form and display a message.
Next I would build the SQL Queries for the action and also the query to undo those changes.
$sql_fwd = "UPDATE ticket
SET idticket_status = 1
WHERE idticket = '".$c_get['id']."';";
$sql_bwd = "UPDATE ticket
SET idticket_status = 0
WHERE idticket = '".$c_get['id']."';";
Having that I run the UPDATE on ticket and insert a new entry in my new table for logging.
With that I can try to catch possible overwrites while two users are editing the same ticket in the same time and for my history I could simply look up the keys and values and generate some kind of list. Also having the SQL_BWD I simply can undo changes.
My questions to that would be:
Would it be noticeable doing an additional select everytime I want to update something?
Do I lose some benefits I would have with triggers?
Are there any big disadvantages
Are there any functions on my mysql server or with php which already do something like that?
Or is there might be a much easier way to do something like that
Is maybe a slight change to my trigger I've now already enough?
If I understad this right MySQL is only performing an update if the value has changed but the trigger is executed anyways right?
If I'm able to change the trigger, can I still prevent somehow the overwriting of data while 2 users try to edit the ticket the same time on the mysql server or would I do this anyways with PHP?
Thank you for the help already
Another approach...
When a worker starts to make a change...
Store the time and worker_id in the row.
Proceed to do the tasks.
When the worker finishes, fetch the last worker_id that touched the record; if it is himself, all is well. Clear the time and worker_id.
If, on the other hand, another worker slips in, then some resolution is needed. This gets into your concept that some things can proceed in parallel.
Comments could be added to a different table, hence no conflict.
Changing the priority may not be an issue by itself.
Other things may be messier.
It may be better to have another table for the time & worker_ids (& ticket_id). This would allow for flagging that multiple workers are currently touching a single record.
As for History versus Current, I (usually) like to have 2 tables:
History -- blow-by-blow list of what changes were made, when, and by whom. This is table is only INSERTed into.
Current -- the current status of the ticket. This table is mostly UPDATEd.
Also, I prefer to write the History directly from the "database layer" of the app, not via Triggers. This gives me much better control over the details of what goes into each table and when. Plus the 'transactions' are clear. This gives me confidence that I am keeping the two tables in sync:
BEGIN; INSERT INTO History...; UPDATE Current...; COMMIT;
I've answered a similar question before. You'll see some good alternatives in that question.
In your case, I think you're merging several concerns - one is "storing an audit trail", and the other is "managing the case where many clients may want to update a single row".
Firstly, I don't like triggers. They are a side effect of some other action, and for non-trivial cases, they make debugging much harder. A poorly designed trigger or audit table can really slow down your application, and you have to make sure that your trigger logic is coordinated between lots of developers. I realize this is personal preference and bias.
Secondly, in my experience, the requirement is rarely "show the status of this one table over time" - it's nearly always "allow me to see what happened to the system over time", and if that requirement exists at all, it's usually fairly high priority. With a ticketing system, for instance, you probably want the name and email address of the users who created, and changed the ticket status; the name of the category/classification, perhaps the name of the project etc. All of those attributes are likely to be foreign keys on to other tables. And when something does happen that requires audit, the requirement is likely "let me see immediately", not "get a database developer to spend hours trying to piece together the picture from 8 different history tables. In a ticketing system, it's likely a requirement for the ticket detail screen to show this.
If all that is true, then I don't think history tables populated by triggers are a good idea - you have to build all the business logic into two sets of code, one to show the "regular" application, and one to show the "audit trail".
Instead, you might want to build "time" into your data model (that was the point of my answer to the other question).
Since then, a new style of data architecture has come along, known as CQRS. This requires a very different way of looking at application design, but it is explicitly designed for reactive applications; these offer much nicer ways of dealing with the "what happens if someone edits the record while the current user is completing the form" question. Stack Overflow is an example - we can see, whilst typing our comments or answers, whether the question was updated, or other answers or comments are posted. There's a reactive library for PHP.
I do understand that disk space is cheap and I should not worry about it but in order to retrieve some kind of log or nice looking history for the user is painful, at least for me.
A large history table is not necessarily a problem. Huge tables only use disk space, which is cheap. They slow things down only when making queries on them. Fortunately, the history is not something you'd use all the time, most likely it is only used to solve problems or for auditing.
It is useful to partition the history table, for example by month or week. This allows you to simply drop very old records, and more important, since the history of the previous months has already been backed up, your daily backup schedule only needs to backup the current month. This means a huge history table will not slow down your backups.
With that I can try to catch possible overwrites while two users are editing the same ticket in the same time
There is a simple solution:
Add a column "version_number".
When you select with intent to modify, you grab this version_number.
Then, when the user submits new data, you do:
UPDATE ...
SET all modified columns,
version_number=version_number+1
WHERE ticket_id=...
AND version_number = (the value you got)
If someone came in-between and modified it, then they will have incremented the version number, so the WHERE will not find the row. The query will return a row count of 0. Thus you know it was modified. You can then SELECT it, compare the values, and offer conflict resolution options to the user.
You can also add columns like who modified it last, and when, and present this information to the user.
If you want the user who opens the modification page to lock out other users, it can be done too, but this needs a timeout (in case they leave the window open and go home, for example). So this is more complex.
Now, about history:
You don't want to have, say, one large TEXT column called "comments" where everyone enters stuff, because it will need to be copied into the history every time someone adds even a single letter.
It is much better to view it like a forum: each ticket is like a topic, which can have a string of comments (like posts), stored in another table, with the info about who wrote it, when, etc. You can also historize that.
The drawback of using a trigger is that the trigger does not know about the user who is logged in, only the MySQL user. So if you want to record who did what, you will have to add a column with the user_id as I proposed above. You can also use Rick James' solution. Both would work.
Remember though that MySQL triggers don't fire on foreign key cascade deletes... so if the row is deleted in this way, it won't work. In this case doing it in the application is better.

Confirm changes and additions to sql database via php?

I have a input form where people can add data about media to the SQL database via web. My question is - is there a way to confirm all the added data?
Example:
Unknown person fills out the form with spam and presses the submit button, I get a message about (or must confirm) the information before it is send to the sql database.
If you are properly building your SQL inserts such that you are protected against SLQ injection, etc., and your goal is to moderate the content, then this is as simple as adding a column to your table called "confirmed" with a default value of "0". Your viewing functions are then checking this value (if $confirmed)...) and no input is viewable until after you've set the confirmed flag. You can delete during moderation or even have a garbage collector cron job that deletes unconfirmed entries older than a preset time.
If you are doing this because you're worried about data getting into your database that can corrupt the database (SQL injection and other nefarious problems), then moderating the input is a very time-consuming solution. You should read up on preparing queries to avoid these problems.
There's three basic options here depending on your particular needs.
Insert into the table with a conditional flag that needs to be set by "confirming" the entries. This requires periodically purging unconfirmed entries after some amount of grace time, typically a day, to avoid cluttering up data with garbage. This can make searching difficult as you'll have to include this flag in all indexes in order to maintain performance and avoid showing non-confirmed data.
The second option is to take all the parameters, package them up as either a singular JSON injected in a hidden field, or each element rendered as a hidden field with identical names from the previous submission. The confirmation process will then re-post these parameters with an additional "confirmed" step.
The third option is to do this all client-side using JavaScript, jQuery, or some kind of front-end framework like Angular or React. This avoids the round-trip to the server, and the server does not have to do any additional work to verify that things are confirmed.

Server side validation idea, searching for a better way to validate server side form submission

I want to create a strong server side validation for my website. Specially to prevent a single user commenting on a post multiple time. Or prevent submitting single data to the database more than one time.
For this I thought It would be nicer if a single user to be blocked for 10 seconds to interact with the database, after his last interaction.
1> Is there any other way to prevent this error or spam protection from server side ?
2> Will it be ok to store the time of post and check the next interaction availability by matching current time and that time on database or there is another way ?
Thank you in advance for helping me in this tiny research !
Use Eloquent events and return false if the user should be stopped.
Comment::creating(function()
{
// Check if the user has posted another comment within the last 10 seconds
// e.g.:
if (Comment::where('user_id', $userId)->where('created_at', '>=', Carbon::now()->subSeconds(10))->count()) return false;
});
Specially to prevent a single user commenting on a post multiple time. Or prevent submitting single data to the database more than one time
This is trivial to enforce at the database tier (assuming you're using a relational database). You could construct the logic to control this in PHP - but it is complex and unnecessary.
or spam protection from server side ?
Yes, of course you can validate data server-side - but you'll need to be a bit more specific about what you're trying to achieve. There are lots of tools like Spamassassin and Akismet which are very sophisticated, well tested and easy to integrate in PHP.
I want to create a strong server side validation for my website.
Specially to prevent a single user commenting on a post multiple time.
The general term for that on the database side is constraint. If you want to limit each user to one comment per post, you'd use either a primary key constraint or a unique constraint. For example, if you had a table named "comments", that table would likely contain
a foreign key constraint to the table of posts (because a comment is about a particular post) and
a foreign key constraint to the table of users (because each comment comes from a particular user).
Table: comments
post_id user_id
--
1 1
1 2
1 3
2 7
Enforce that constraint with either primary key (post_id, user_id) or with unique (post_id, user_id).
Or prevent submitting single data to the database more than one time.
I can imagine a few different meanings for that requirement. You might want to edit your question, and add some more details.
For this I thought It would be nicer if a single user to be blocked for 10 seconds to interact with the database, after his last interaction.
These two "requirements" mean radically different things.
I want to limit the user to one comment per post, and only one comment per post.
I want to limit the user to one comment per post every 10 seconds. So if the user is patient, I want to let them enter 137 comments per post.
This can be done with triggers in the back end, or with application code in the front end. SQL database management systems don't yet generally support declarative constraints among rows or among tables.

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.

Tracking data changes

I work on a market research database centric website, developed in PHP and MySQL.
It consists of two big parts – one in which users insert and update own data (let say one table T with an user_id field) and another in which an website administrator can insert new or update existing records (same table).
Obviously, in some cases end users will have their data overridden by the administrator while in other cases, administrator entered data is updated by end users (it is fine both ways).
The requirement is to highlight the view/edit forms with (let’s say) blue if end user was the last to update a certain field or red if the administrator is to “blame”.
I am looking into an efficient and consistent method to implement this.
So far, I have the following options:
For each record in table T, add another one ( char(1) ) in which write ‘U’ if end user inserted/updated the field or ‘A’ if the administrator did so. When the view/edit form is rendered, use this information to highlight each field accordingly.
Create a new table H storing an edit history containing something like user_id, field_name, last_update_user_id. Keep table H up-to-date when fields are updated in main table T. When the view/edit form is rendered, use this information to highlight each form field accordingly.
What are the pros/cons of these options; can you suggest others?
I suppose it just depends how forward-looking you want to be.
Your first approach has the advantage of being very simple to implement, is very straightforward to update and utilize, and also will only increase your storage requirements very slightly, but it's also the extreme minimum in terms of the amount of information you're storing.
If you go with the second approach and store a more complete history, if you need to add an "edit history" in the future, you'll already have things set up for that, and a lot of data waiting around. But if you end up never needing this data, it's a bit of a waste.
Or if you want the best of both worlds, you could combine them. Keep a full edit history but also update the single-character flag in the main record. That way you don't have to do any processing of the history to find the most recent edit, just look at the flag. But if you ever do need the full history, it's available.
Personally, I prefer keeping more information than I think I'll need at the time. Storage space is very cheap, and you never know when it's going to come in handy. I'd probably go even further than what you proposed, and also make it so the edit history keeps track of what they changed, and the before/after values. That can be very handy for debugging, and could be useful in the future depending on the project's exact needs.
Yes, implement an audit table that holds copies of the historical data, by/from whom &c. I work on a system currently that keeps it simple and writes the value changes as simple name-value string pairs along with date and by whom. It requires mandatory master record adjustment, but works well for tracking. You could implement this easily with a trigger.
The best way to audit data changes is through a trigger on the database table. In your case you may want to just update the last person to make the change. Or you may want a full auditing solution where you store the previous values making it easy to restore them if they were made in error. But the key to this is to do this on the database and not through the application. Database changes are often made through sources other than the application and you will want to know if this happened as well. Suppose someone hacked into the database and updated the data, wouldn't you like to be able to find the old data easily or know who did it even if he or she did it through a query window and not through the application? You might also need to know if the data was changed through a data import if you ever have to get large amounts of data at one time.

Categories