Confirm changes and additions to sql database via php? - 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.

Related

PHP + MySQL/MariaDB + avoid race condition [duplicate]

This question already has answers here:
How to make sure there is no race condition in MySQL database when incrementing a field?
(2 answers)
Lock file/content while being edited in browser.
(1 answer)
Closed 4 years ago.
I've developed a web application using Apache, MySQL and PHP.
This web app allows multiple users' to login to the application.
Then, through the application, they have access to the Database.
Since race conditions may apply when two or more users try to SELECT/UPDATE/DELETE the same information (in my case a row of a Table), I am searching for the best way to avoid such race conditions.
I've tried using mysqli with setting autocommit to OFF and using SELECT .... FOR UPDATE, but this fails to work as -to my understanding- with PHP, each transaction commits automatically and each connection to the db is being auto released when the PHP -->html page is provided/loaded for the user.
After reading some posts, there seem to be two possible solutions for my problem :
Use PDO. To my understanding PDO creates connections to the DB which are not released when the html page loads. Special precautions should be taken though as locks may remain if e.g. the user quits the page and the PDO connection has not been released...
Add a "locked" column in the corresponding table to flag locked rows. So e.g. when an UPDATE transaction may only be performed if the corresponding user has locked the row for editing. The other users shall not be allowed to modify.
The main issue I may have with PDO is that I have to modify the PHP code in order to replace mysqli with PDO, where applicable.
The issue with the scenario 2 is that I need to also modify my DB schema, add additional coding for lock/unlock and also consider the possibility of "hanging" locked rows which may result in additional columns to be added in the table (e.g. to store the time the row was locked and the lockedBy information) and code as well (e.g. to run a Javascript at User side that will be updating the locked time so that the user continuously flags the row while using it...)
Your comments based on your experience would be highly appreciated!!!
Thank you.
It might be an opinion instead of a technical answer, but too long to write it as a comment.
I want to think it like booking a seat in a movie or a flight: When an user selects a seat and presses next, the seat will be reserved for that user for a certain amount of time, and when user doesn't finish in the given time, it gets a timeout exception without processing further. You can use an edit button besides the row, and when the user clicks it, on the server side, you check if the row is reserved to someone else, and if not, reserve it to the user. Other users won't get an edit form when they also click the edit button after that user. I don't know how database systems handle this though.
But, one way to make it sure, re-read the row after user edits and commits it to display the user. If any lock mechanism prevented the row from being updated, the user will also know it by not seeing the change in the row.

I have found a $_GET['var'] == an SQL statement - What are the risks?

I have discovered that some old (2009) code that was written for a website, did, under certain circumstances on a search query save the SQL as a a $_GET variable!
When the search was carried out, the details are POSTED and then sanitized, and the results are paginated with the LIMIT clause in MySQL. If there is more than one page (ie +30 results) the pages are anchor links in the HTML with a GET var containing the SQL statement.
I know, this is absolutely not the way to do this. It's old code I've just seen it by chance. This needs to be fixed.
So I've fixed it, sanitized it and used an alternative method to reload the SQL, BUT:
My question is thus:
The page outputs the data relating to thumbnail images, all data is output as named array var (the original clause is a SELECT * clause), so if someone does abuse the GET variable, the page itself will only output the columns named,
I have managed to DELETE rows from the DB using the GET abuse, I would like to think the abuse is only effective if the result is not involving any returned output (such as DELETE) but I don't know; so given that the user can input anything into the GET clause but only get the displayed output of what's coded (ie named columns in a 30 row array) -- what other abuses can this gaping hole be open to?
Further details: The code is MySQLi
A tool like SQLMAP can probably take over the entire server and do with it whatever the user wants.
Having an unsanitized database input isn´t even hacking anymore, it´s waiting for someone to run a script on your machine and basically own it from that point on.
What the attacker can do depends on your database configuration and database user access. If you create a new user with a permission to only SELECT that one specified table, and use that user for that particular script, the harm it can do is reading data from that table.
Still this is bad practice. Never use it.

PHP - Prevent client from tampering the ID of a form

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 %.

"Last minute subscription" project PHP/MySQL atomicity issues

I'm working on an AJAX application. The user clicks a button and his name is saved into the database and shown inside a <div>, whose content is fetched from the database by means of an AJAX Long Polling. The database also contains a timestamp which represents an expiration: subscriptions beyond that timestamp must not be accepted. There is also a limit for users to subscribe.
I have a PHP script that is called by an AJAX request, this script queries the database and checks for expiration (the timestamp of the click is computed by JavaScript and sent via AJAX). It also checks for user limit: i have a N-to-N relationship between Users and Products (to subscribe for). These tasks obviously take time and I'm worried about possible concurrency problems. Should I use database transactions? What technique could I use to ensure the atomicity of this operation?
It depends on the kind of work that is done those "long" tasks.
Generic info:
If you're only inserting user driven data and data generated in PHP without it being read and/or cross-correlated with data fetched from the DB then transactionality should not be an issue.
If you're updating data and cross-correlating it with other elements in the DB then you need to start using transactions and to carefully choose the isolation levels of the transactions you plan on using.
Transactions can seriously affect speed when concurrency rises. Choosing a very safe isolation level may be safer than needed for your application and you may be adding a lot of unnecessary work to the MVCC.
Also using transactions as separate PHP api calls and managing the rollback logic in the application increases the overall duration of the transaction because it adds all the processing delays generated by PHP. If you can compact DB communications into a set of queries requested in one communication it would be better.
Case info:
Let's consider this scenario: there are 8 slots, 7 users subscribed. Two users click the subscribe button almost simultaneously. When the control script is launched for the last clicking user, the query for the subscription of the first clicking user might still be executed. This would imply that the system accepts both users as valid subscriptions.
This falls into the second case I explained, the case when you're cross-correlating user driven data with what you have in the DB. You're reading the state of the db before you commit the user drive data, so yes you would need transactions in this case.
There may be a possibility to speculate the inherent atomicity of one update statement. Any UPDATE table_name SET x = x+1 WHERE a = 'value'; is guaranteed to be atomic. You can use this to your advantage.
All subscribing PHP threads must first decrement a subscriber count. If the number of affected rows on the decrement is not 0 that means that the decrement was successful and they can carry on submitting the user-related data, else inform the user he was 0.3ms too slow.

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.

Categories