I'm using the ezSQL PHP class for MySQL queries. Since all of my queries pass through the $ezsql->query() function, I thought it would be a good idea to implement a method to block common SQL injection techniques from $ezsql->query().
For example, the most common one is probably 1=1. So this regular expression should be able to block all variations of that:
preg_match('/(?:"|\')?(\d)(?:"|\')?=(?:"|\')?\1(?:"|\')?/',$query);
This would block "1"="1", '1'=1, 1=1, etc.
Is this a good idea? If so, what are some other common patterns?
Edit: Forgot to mention, I do use validation and sanitation. This is just an extra precaution.
Is this a good idea?
No. For two reasons:
You're doing it wrong (yes you just failed with your bare approach of a SQL blacklist). And no, I won't tell you how you could improve that because of 2:
It's a blacklist approach. You should not use a blacklist approach inside the database class itself. That's no added pre-caution, it's just useless. Blacklist could be added additionally at the request level of the webserver for example.
Instead use an existing blacklist, don't re-invent the wheel. If you want to learn how to develop your own SQL blacklist layer, help with the development of such existing components. This sort of security is not out-of-the-box so that you can just throw in a question like yours and you can actually expect concrete answers. Take care.
Is this a good idea?
Definitely NO.
Every time I see such a suggestion on an internet forum, I am wondering, what if the software this forum runs on followed such a pattern? A poor inventor would be just unable co come up with their solution, because software would block the post!
extra precautions wouldn't hurt. Better safe than sorry.
As I pointed out above, it apparently hurts. A database that cannot process some odd portions of data is a nonsense.
Besides, I do believe that only knowledge can make you safe.
Not random moves out of some vague ideas but sane and reasonable actions.
As long as you escape and quote the data that goes to the query and as long as you set the proper encoding for the escaping function, there is no reason to sorrow.
As long as you are using prepared statements to add your data to the query, there is no reason to sorrow.
As long as you are filtering SQL identifiers and keywords based on hardcoded whitelist, there is no reason to sorrow.
Related
I know this topic has been covered to death but I would like some feedback from the community regarding security within our web application.
We have standard LAMP stack web app which contains a large number of database queries which are executed using mysqli_query. These queries are not parameterized and at the moment but there is some naive escaping of the inputs using addslashes.
I have been tasked with making this system safer as we will be penetration tested very shortly. The powers above know that parameterized queries are the way to go to make the system safer however they don't want to invest the time and effort into re-writing all the queries in the application and also changing the framework we have to make them all work correctly.
So basically I'm asking what my options are here?
I've run mysqli_real_escape_string over the inputs. I've setup a filter which doesn't allow words like SELECT, WHERE, UNION to be passed in which I guess makes it safer. I know mysqli_query only allows one query to be run at once so there's some security there (from concatenating updates onto the end of of selects).
Do I have any other options here?
Edit: I should probably add that if anyone is able to provide an example of an attack which is completely unavoidable without parameterized queries that would also be helpful. We have a query which looks like this:
SELECT
pl.created
p.LoginName,
pl.username_entered,
pl.ip_address
FROM loginattempts pl
LEFT JOIN people p ON p.PersonnelId = pl.personnel_id
WHERE p.personnelid = $id
AND pl.created > $date1
AND pl.created < $date2
I've substituted a UNION query into the $id UNION SELECT * FROM p WHERE 1 = 1 sort of thing and I can prevent that by not allowing SELECT/UNION but then I'm sure there are countless other types of attack which I can't think of. Can anyone suggest a few more?
Update
I've convinced the powers that be above me that we need to rewrite the queries to parameterized statements. They estimate it will take a few months maybe but it has to be done. Win. I think?
Update2
Unfortunately I've not been able to convince the powers that be that we need to re-write all of our queries to parameterized ones.
The strategy we have come up with is to test every input as follows:
If the user supplied input is_int that cast it as so.
Same for real numbers.
Run mysqli_real_escape_string over the character data.
Change all the parameters in the queries to quoted strings i.e.
WHERE staffName = ' . $blah . '
In accordance with this answer we are 100% safe as we are not changing the character set at any time and we are using PHP5.5 with latin1 character set at all times.
Update 3
This question has been marked as a duplicate however in my mind the question is still not followed answered. As per update no.2 we have found some strong opinion that the mysqli_real_escape string function can prevent attacks and is apparently "100% safe". No good counter argument has since been provided (i.e. a demonstration of an attack which can defeat it when used correctly).
check every single user input for datatype and where applicabile with regular expressions (golden rule is: never EVER trust user input)
use prepared statements
seriously: prepared statements :)
it's a lot of work especially if your application is in bad shape (like it seems to be in your case) but it's the best way to have a decent security level
the other way (which i'm advising against) could be virtual patching using mod_security or a WAF to filter out injection attempts but first and foremost: try to write robust applications
(virtual patching might seem to be a lazy way to fix things but takes actually a lot of work and testing too and should really only be used on top of an already strong application code)
Do I have any other options here?
No. No external measure, like ones you tried to implement, has been proven to be of any help. Your site is still vulnerable.
I've run mysqli_real_escape_string over the inputs
Congratulations, you just reinvented the notorious magic_quotes feature, that proven to be useless and now expelled from the language.
JFYI, mysqli_real_escape_string has nothing to do with SQL injections at all.
Also, combining it with existing addslashes() call, you are spoiling your data, by doubling number of slashes in it.
I've setup a filter which I guess makes it safer.
It is not. SQL injection is not about adding some words.
Also, this approach is called "Black-listing" it is proven to be essentially unreliable. A black list is essentially incomplete, no matter how many "suggestions" you can get.
I know mysqli_query only allows one query to be run at once so there's some security there
There is not. SQL injection is not about adding another query.
Why did I close this question as a duplicate for "How can I prevent SQL-injection in PHP?"?
Because these questions are mutually exclusive, and cannot coexist on the same site.
If we agree, that the only proper answer is using prepared statements, then a question asks "How can I protect using no prepared statements" makes very little sense.
At the same time, if the OP manages to force us to give the positive answer they desperately wants, it will make the other question obsoleted. Why use prepared statements if everything is all right without them?
Additionally, this particular question is too localized as well. It seeks not insight but excuse. An excuse for nobody but the OP personally only. An excuse that let them to use an approach that proven to be insecure. Although it's up to them, but this renders this question essentially useless for the community.
After many attempts of writing a code that can sanatize/validate $_POST["input"] in a PHP form I have to ask about it in general, because every attempt didn't work as I expected. I really have tried much and i just started to exercise with coding 2 months ago (html, css, bootstrap, wordpress, php). I hope you can tell me, as you can see, what is the most common or "best" way to sanatize a php form.
I have re-writed some OOP PDO form validation, which i couldn't get runned as i integrated it into a new homepage, because my OOP skills = 0.
It was build with classes, but i didn't see any prepared statement, which surprised me because prepared statements are idolized in the web.
Which is the better way and could you tell me why?
I hope you can answer my question and explain a little bit how i can handle it in a "pro-way", which in the best case is safe, because it is a hurdle for me.
Thank you for your help.
First of all, you should never connect validation and "sanitization" in any context. That's two completely different matters, which, alas, confuse too many people.
Validation indeed have to be applied to the form data and there is no common way to do it. Just use your common sense, business logic needs and framework guidelines.
While "sanitization" is a different matter. Even the word itself is the biggest blunder of PHP folks, always misused and confused.
And the best way to "sanitize" is not to to sanitize at all. Because
You can't "sanitize" your data, whatever you mean under the term.
Whatever "sanitization" will rather spoil the data.
There are actually many destinations this data may be for. You can't have one-for-all solution.
It is destination, not source that matters. Means you should use prepared statements not for POST variables but for SQL queries. BIG difference.
You should format, not "sanitize". Format according to the rules of the certain current destination.
To format data for the SQL query you have to use prepared statements.
To format your data for other destinations you have to follow their rules. And again, not "post form" but all data, despite of its source.
The Answer of "Your Common Sense" is definitely correct.
So you should validate your form first (clientside), there are a lots of small validation libs like e.g.: http://rickharrison.github.io/validate.js/
When it was posted you have to check if this data, is like you expected it.
E-Mail is just an e-mail, name ist just a string without XSS or SQL Injection stuff.....
So it depends on the destination like the above answer said.
To filter some post values there is for example: http://php.net/manual/en/function.filter-var.php
You can also use full frameworks or libraries against sql Injection and XSS stuff. You should use MySQLi prepared statements an some other stuff against XSS, like: HTMLPurifier http://htmlpurifier.org/
These are just some examples, if you interested I recommend you reading this page: https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
I am considering allowing users to insert their own REGEXP pattern which will be used in a Mysql query. I am well aware of sql injection risks, and I know there is no way of passing the regexp pattern value as an argument to a prepared statement.
Is there a waterproof way to safely allow users to provide their own regexp pattern for in the sql query, or should I abandon this idea?
I am working with PHP, by the way, so I am basically asking if it is possible in PHP to make sure the pattern is valid, genuine and harmless.
Good question! I experienced that in general users are not really 'educated' enough to enter 'real' regular expressions. The 'standard' user considers the asterisk already as being really complicated. Patterns like /^([^[0-9]+\s[a-z]*)/i are very rarely used by the 'average' user. You wll probably be better advised to provide the user with simpler meta-characters as wildcards. Unless you want to use the tool as an administrator tool ... for people who know what they are doing.
I haven't done this for mysql, but I've done something similar once for another dbms
what I did was:
determine what version/dialect of regex the db actually uses (there are several flavors. you could go for a restricted one like POSIX basic)
try to compile the regex in the application first (in my case it was java). if it throws an exception at this point, you know it's bad.
execute it on the db
additionally, you could:
first execute it with a "sandbox" user (one using a dummy schema, with no rights to do anything dangerous) and see what happens.
restrict it some more (validate it against a whitelist of allowed characters) e.g don't allow dangerous things like single quotes, semicolons, etc. I imagine php/mysql allows various encodings, so you'll have to deal with that too.
That being said I don't think you can completely remove the risk. edit: especially if you want to avoid denial-of-service attacks too.
I am trying to figure out which functions are best to use in different cases when inputting data, as well as outputting data.
When I allow a user to input data into MySQL what is the best way to secure the data to prevent SQL injections and or any other type of injections or hacks someone could attempt?
When I output the data as regular html from the database what is the best way to do this so scripts and such cannot be run?
At the moment I basically only use
mysql_real_escape_string();
before inputting the data to the database, this seems to work fine, but I would like to know if this is all I need to do, or if some other method is better.
And at the moment I use
stripslashes(nl2br(htmlentities()))
(most of the time anyways) for outputting data. I find these work fine for what I usually use them for, however I have run into a problem with htmlentities, I want to be able to have some html tags output respectively, for example:
<ul></ul><li></li><bold></bold>
etc, but I can't.
any help would be great, thanks.
I agree with mikikg that you need to understand SQL injection and XSS vulnerabilities before you can try to secure applications against these types of problems.
However, I disagree with his assertions to use regular expressions to validate user input as a SQL injection preventer. Yes, do validate user input insofar as you can. But don't rely on this to prevent injections, because hackers break these kinds of filters quite often. Also, don't be too strict with your filters -- plenty of websites won't let me log in because there's an apostrophe in my name, and let me tell you, it's a pain in the a** when this happens.
There are two kinds of security problems you mention in your question. The first is a SQL injection. This vulnerability is a "solved problem." That is, if you use parameterized queries, and never pass user supplied data in as anything but a parameter, the database is going to do the "right thing" for you, no matter what happens. For many databases, if you use parameterized queries, there's no chance of injection because the data isn't actually sent embedded in the SQL -- the data is passed unescaped in a length prefixed or similar blob along the wire. This is considerably more performant than database escape functions, and can be safer. (Note: if you use stored procedures that generate dynamic SQL on the database, they might also have injection problems!)
The second problem you mention is the cross site scripting problem. If you want to allow the user to supply HTML without entity escaping it first, this problem is an open research question. Suffice to say that if you allow the user to pass some kinds of HTML, it's entirely likely that your system will suffer an XSS problem at some point to a determined attacker. Now, the state of the art for this problem is to "filter" the data on the server, using libraries like HTMLPurifier. Attackers can and do break these filters on a regular basis; but as of yet nobody has found a better way of protecting the application from these kinds of things. You may be better off only allowing a specific whitelist of HTML tags, and entity encoding anything else.
This is one of the most problematic task today :)
You need to know how SQL injection and other attackers methods works. There are very detailed explanation of each method in https://www.owasp.org/index.php/Main_Page and also whole security framework for PHP.
Using specific security libraries from some framework are also good choice like in CodeIgniter or Zend.
Next, use REGEXP as much as you can and stick pattern rules to specific input format.
Use prepared statements or active records class of your framework.
Always cast your input with (int)$_GET['myvar'] if you really need numeric values.
There are so many other rules and methods to secure your application, but one golden rule is "never trust user's input".
In your php configuration, magic_quotes_gpc should be off. So you won't need stripslashes.
For SQL, take a look at PDO's prepared statements.
And for your custom tags, as there are only three of them, you can do a preg_replace call after the call of htmlentities to convert those back before your insert them into the database.
I just wanted to know what are some basic PHP security techniques I should use when creating a web page that accepts articles?
I'm fairly new to PHP and was wondering what will hold the fort down until I'm a security expert?
There are two fronts to consider when accepting user-generated text that will later be displayed.
First off, you need to protect your database from injection attacks. There's a simple PHP function for this: mysql_real_escape_string() will usually suffice to protect your database from injection when passing this string in to store as a field value.
From there, you have to be careful about your display, as a user who is allowed to upload HTML code can do nasty things to other users when that code gets displayed. If you're doing plaintext articles, you can simply htmlspecialchars() the resulting text. (you'll also probably want to convert newlines to tags.) If you're using a formatting solution, such as the Markdown engine used on this site, those solutions will usually provide HTML sanitization as a function of the engine, but be sure to read the documentation and make sure.
Oh, make sure you're also verifying your GET/POST variables used to submit the articles. That goes without saying, and the verification performed is going to need to be tailored to what your site is doing with its logic.
This is to broad, maybe you should try to narrow it a bit.
What kind of security?
For passwords?
Do you want to restrict some stuff?
SQL Injection?
HTML Injection?
Cross domain security?
Well, as mentioned in the other answers, there are a number of different fronts in which your PHP scripts can be compromised.
Here are just a couple:
SQL Injection
Cross site scripting
There are a number of ways to deal with each. Here are some things to look at:
Suhosin
eval()
There is a lot to know, and you should start as soon as you can.
For one, if you accept articles (and probably use a WYSIWYG and are accepting HTML), use something to parse the content and strip out things that could leave you vulnerable to XSS and the like.
An example is HTML Purifier.
It might be wise to start by using a framework like Drupal or CakePHP. That way you can both learn from the way they've implemented security and take advantage of the fact that it's already been done. The learning curve is steep enough without having to roll your own authentication mechanisms etc.
maybe two tips could help you get more secure websites
create two users in your database, read only account to make only selects and counts, and write account when you have to do updates, inserts or deletes.
when you have to insert into database or delete, sanitize inputs, use mysql prepared statements or assert values that arrive via post or get this way :
if(!empty($_GET["integer_like_id_value"]){
$integer_id_value = (int)$_GET["integer_like_id_value"];
}else{
// that stuff seems not to be legit, die application, log error ? whatever
die();
}
Top 7 PHP Security Blunders
When your project is ready for public usage, it is generally a good idea to set error_reporting(0);
It won't provide more security, but it makes it lot harder (usually) for bad guys to find possible security problems with your site.