I've just hit a weird display issue.
I have an ecommerce site which allows the user to add free text in a description field. This value is stored in an mysql database and later read out to the screen in a description.
During some testing I've found that if the user puts 'select * from table' it is stored and returned correctly but the html is turning it into
<span class="idesc break-word">TESTING TESTING %$#$!OIUOQI#UQO#)( <select *="" from="" table=""></select></span>
which in turn appears as an empty select drop down box.
I already use ? bind variables in the php to mysql code so firstly:
Is there something else I should be doing to protect against dodgy data entry?
Is this indicative that I could be open to other such attacks?
If values of the field that was created in that manner are being passed further down he application and can end up sent to database than yes you are open to SQL injection attacks.
Is there some code that is looking for "select" and decides that a field should be created from that? If yes, that looks somewhat dangerous and there could be more areas where this ecommerce app makes potentially dangerous decisions.
Binding is a good step in preventing unexpected data types from being entered, but going a step further like limiting some characters e.g. ;<> is also a good way. What worries me with your example is that you were not expecting a select field, but got one; that means that once broken that mechanism could be further exploited to interact with your database.
Related
I'm making a website for renting a car using PHP and MySQL .But I'm stuck, because I don't know how to combine car details and booking form details and show it in PHPMyAdmin when user submits the form.
Representation
You need to create relational representation in your MySQL database, like a table for cars, of the like of
cars(id, ...)
Where the ... represents whatever details you intend to store.
Storing a car
You need to create a PHP script that takes car details as input and stores cars as output. Since you already told us that you have a form, you will most likely use $_POST (an array with your named form elements for the form that you have submitted) as the input, but it is strongly recommended that you separate your functionality part from the definition of your input. So, you will most likely have a function/method (a standalone function or a method of a class) that will look something like this:
function storeCar($input) {
//...
}
where $input is an associative array and you actually store the values. Of course, pay attention to SQL injection and XSS injection as possibilities. These are possible vulnerabilities that infest the codes of most beginners. You can used parameterized queries to prevent SQL injection and htmlspecialchars to protect against XSS injection.
Your code will end up executing an insert into ... type of command once you POST your form.
Loading cars
You can execute select * from cars to see what your cars' details are (but it's better to list only the columns you are interested about) at any places that are connected to MySQL, including PHPMyAdmin. Or, in some UIs, such as PHPMyAdmin you can click on table names.
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.
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.
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 3 years ago.
I asked this question earlier Preventing SQL Injection in dynamical SQL, but was not clear which resulted in the question being closed, and was later told in the comments that I should ask the question again.
A requirement of my PHP/MySQL application is to allow all users to create their own multiple "views" of the data. These views are not traditional SQL views, but performed by the application.
For instance, the user could create a view and provide the following criteria:
Name of the view.
Desired records per page.
Which columns to display by using a dropdown menu.
Any filters for the results. A first dropdown menu is used to select the column, a second dropdown menu is used to select the operator (equals, not equal, greater than, etc), and then either a third dropdown menu is used to select the value to be matched or the user directly enters the value to be matched.
Whether the records should be grouped on a given column.
Based on the user's selection, various tables might need to be joined to the query to support the select, where, and group by clauses, and the application is used to eliminate duplicate table joins should they exist.
After the user has finished configuring their views, there is a dropdown menu which allows them to select their desired view, and the appropriate results are displayed.
I have implemented this functionality by storing the user's selections in several tables, and also storing the resultant query (actually, I store individual sections of the query in various columns so I may count the total results in an initial query and return the correct number of results in a second query) in a SQL table. Note that I am storing the user's selections only so that I can allow them to edit their view requirements, and not to create the resultant query on the fly (more on this later).
I recognize that I have to be very careful as doing this can be prone to SQL injunction. For instance, I can't just escape the user's input using PDO and store it in the database, and then later retrieve the data and use it in a query since when it is retrieved, it is no longer escaped.
To combat this risk, I limit user input to integers wherever possible, and typecast them where possible. Where user inputs are percents and dollars, I multiply by 100, typecast the resultant as an integer, and then divide by 100 before storing it. A couple of the filters require text as the value in the WHERE clause, and as stated earlier, escaping the data is not enought, and instead I am using $user_input= preg_replace('/[^a-z0-9,]/i', '', $_POST['user_input']); to make safe.
Is this an accepted method to implement this functionality? Is there an easier way to ensure the user input is safe? My earlier post Preventing SQL Injection in dynamical SQL indicated that this type of practice should never be attempted, however, I don't know how else to do it. Are there any other steps I should take to prevent injection?
Or maybe I should not create a query and store it in a table when the user saves his view configuration, but create the query on the fly using the user's saved values each time the user selects a given view. This would have a negative performance impact and add complicity but I suppose I can do it. Would you recommend using this strategy?
Thank you
Hello I get you I think.
This is what you are looking for:
http://www.php.net/manual/en/function.addslashes.php
$safestring=mysql_real_escape_string($_POST['user_input']);
$safestring=addslashes($safestring);
If you want to make it even more safer, that is the user cannot input html in the input,
use this function after using the above one (i.e. mysql_real_escape_string)
$safestring=htmlspecialchars($safestring);
Now all your use input will stay as it is,
if string is "user's input" it will stay as "user's input" and not change to "users input", so nothing is being replaced, and its still safe.
Regards.
I would like to allow some admins to manually enter SQL statements in a textfield (to get statistic data etc.). On the database layer, I protected the data by creating a user which can only select but not update/delete etc.
I would like to add a second security by checking the inserted SQL for bad words such as DROP, DELETE or UPDATE. I figured out how to do that with preg_match but I would love to have a smart script which can distiguish between a DROP and something like WHERE name = 'DROP 1'
EDIT: I would like to log if an admin tries to uses such statements. That's why I need this second level security check. This is for clarification.
Does anyone know a code snipped which fits this example?
Thanks!!
New Response
Since you updated your question to clarify what you're looking for, I wanted to offer a different solution. Don't worry about what the user is submitting as a query, again, MySQL will spit back an error if they don't have sufficient privs to do something.
Capture that error with mysql_error(), and the error number with mysql_errno(). If the error message says "DROP command denied..." or the error number is 1142 then you know they tried being naughty. Looking for terms within this error is better than looking for terms in their query, as you rightly pointed out that their query can legitimately use the bad words.
Original Response
If your user can only SELECT, then they cannot DROP or DELETE. Looking for these words doesn't add any more security to the mix since the database will reject any queries that aren't explicitly allowed for that given user.
I wouldn't use regular expressions for something as complex as SQL.
I'd start by looking at what SQL parsers are available for PHP, then use one of those to parse and analyze the SQL statements being used.
Try one of these:
http://pear.php.net/package/SQL_Parser
http://sourceforge.net/projects/osqlp/
This is definitely the wrong place to put this level of security in. So long as you have set the database up so the only have SELECT privileges then they cannot change the data in any way. However is you give them any privileges that can change data then no amount of semantic checking on SQL statements will give you security.
Why don't you just create the commands for the stats data and allow the admins to call those commands? Isn't that easier?
Not saying the admins will do harm intentionally but it could happen!