As we know as usual sites use functions like mysqli_query() and mysql's PHP driver does NOT allow multiple queries in a single->query() call (But you can do as many in phpmyadmin SQL running section) so we cannot directly add DELETE/UPDATE/INSERT but abusing of possibilities to modify data under some circumstances. The 1st thing is that in that case I think 80% of potentially being at risk (maybe lost of data) is gone! & the 2nd one is, rely on this knowledge, why most of injecting tutorials are based and focused on multiple queries?
80% of potentially being at risk (maybe lost of data) is gone!
This assumption is wrong.
why most of injecting tutorials are based on multiple queries?
Because it's just a simple understandable example, a proof of concept. Just like one "If John have 2 apples and Mike five...". If real Mike doesn't feel like to spare his apples, it doesn't mean that arithmetics is all wrong.
SQL Injection Concudrum
There are NO conundrum in injections.
There is no point in musings on injections.
There is no percents of risk to be calculated but just a dichotomy: either you have your application compromised or not.
There is just one simple rule - always format your data properly, and you will forget of injections forever.
PHP for a long while has disallowed multiple queries running for a single query() statement. This is just part of preventing sql injection. You must also escape your inputs, use prepared statements, make your table names and columns hard to guess and such.
The simplest example of an sql injection attack does involve a query that's tricked into executing more than one query, but obviously php prevents a lot of such attacks by the limitation already mentioned. However, things like subqueries are still possible, so it's not fool proof. I don't think it's possible to make sql injections altogether impossible as people keep finding new ways to trick scripts.
The best you can do is know how such attacks are done and write your code according to currently accepted best practices to prevent such attacks. If you've done all this and still get hacked, then probably (but not certainly) it wasn't your sql that was the weakest link in your security. From what I understand, more often hackers succeed using social engineering techniques.
Making an un-hackable system is nigh impossible, so the best you can do is make it difficult to hack and thus, not be the 'low hanging fruit' or, in other words, don't be an easy target.
Related
I am going to get into database designing and PHP. But when I do I am very worried about SQL-Injecting. Is there anyway to reverse this when it happens. Like auto reset it, or delete the account thats hacked, or close the databases. Also is there a way that it can be Auto-Tested for intruders?
This is an immensely complex question.
Short answer is: No, if no backups exist
The long answer:
You should mainly focus on how to prevent sql injection, for example using prepared statements is a good method to prevent these attacks. Regardless of potential sql-injection vulnearbilities regular backups should be made and stored at a different physical location. The datacenter of the server with the database might burn down and your data is gone. Though this is very unlikely to happen it is not impossible.
Depending on the importance of the data in your database there are ways (for example cron jobs) to do backups weekly, dayly, every hour and so on. If you have a second server you can write a script that sends the backup to the seconds server or you log in from time to time and download them.
You could also log all interaction and changes in the database but reversing the damage done in this way is not practical.
This link might be interesting for you: Prevent SQL Injection in PHP
If you get a SQL injection the attacker gets the same privileges as your application, they can delete or change whatever they want so basically you're out of luck. You can restore your database from a backup but then you'd lose whatever changes happened between the backup and the attack.
Instead of trying to detect and revert SQL injection you'd better avoid allowing them in the first place, a good way to avoid SQL injections is to use PDO's prepared statements.
To put it simply, if it happens, you pretty much already lost. Disconnect the database from the internet and assess the damage, dump the damaged version for later analysis or whatnot, and restore to the closest non-broken backup, is probably the best course of action in most situations.
But what you should do is prevent it in the first place.
While it is possible to do escaping and/or pattern checks, it is much better to solve it with prepared/parameterized statements and/or object-relational mapping.
A lot of the major frameworks comes with some form of ORM, and unless you are either super-confident about covering all security holes or in a situation where security is completely optional, I seriously recommend you to use something like that.
Aside from SQL injection, this will also protect you from a variety of other security risks, and help you in other ways.
For example, have a look at FuelPHP.
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.
Suppose you have a query looking like this:
SELECT * FROM messages WHERE sender='clean_username'
where the clean_username is received over get/post and sanitized like this:
$clean_username = preg_replace( '/[^A-Za-z0-9_]+/m' , '', $dirty_username );
The above code removes any whitespace (among other things), which means that the valid_username parameter will always only be one word.
What is the simplest way this can be exploited with an injection?
I'm asking this question to better understand how SQL injection works. In my work I stick to the established good practices of using prepared statements and parameterized queries to prevent injections, but I think it's good for people to also have an understanding of how malicious code can be injected in a simple scenario like this.
You can still exploit this using hex coding: stripping spaces is not enough.
I guess this is a somewhat interesting place to start. But consider that preg_match()es are pretty bad for performance on high traffic sites.
Prepared statements and parameterized queries are always the best way to prevent SQL injections.
Example of GET injection using hex coding and no spaces
?id=(1)and(1)=(0)union(select(null),group_concat(column_name),(null)from(information_schema.columns)where(table_name)=(0x7573657273))#
I think you can see the problem above.
I think you already answered the question on your own.
The best way is a standard approach where you use parameterized queries to distinguish between user data and sql command.
In your particular case you assume that a sender username can only consist out of a limited set of ASCII characters. That might work for the moment, and as long as there is no string conversion before, no one can easily close the string apostrophes within the sql statement.
But always consider anticipation of changes. Somebody can rely on your given code in the nearby future and use or modify it and make new assumptions. Your test is actually weak and it can suddenly become dangerous when no one remembers and expects it.
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.
Let's not go so far as to say that I'm paranoid, but I've been spending hour after hour learning how to prevent SQL injections (and XSS for what it's worth).
What I'm wondering is that a SQL injection doesn't seem like it would do permanent harm to my database if I've made daily backups. Doesn't importing yesterday's copy of my tables just restore them and then I can be on my merry way?
As far as actual loss of data goes, you're mostly correct - you'd lose any changes made in the past day, but aside from that you'd be back to a functional database.
However, there are other things that, just because they aren't "lost", doesn't mean it isn't bad that they got compromised. These kinds of things are stuff like user account info (and especially password hashes) - things that people use to protect their accounts and, if discovered by the wrong people, can lead to malicious usage of their information and resources.
That's why you have to work to avoid security breaches in the first place rather than simply rolling back any changes.
This is a very dangerous way to think. Yes, SQL injection attacks will usually trash the database and thus instantly crash your web app, after which you (somewhat) merrily restore from backup and go on your (somewhat) merry way.
On the other hand, they may simply blow away or alter a few records at random, so that it takes you weeks or even months to discover that your data have been getting slowly corrupted over a long period of time. Good luck recovering from that.
Worse still, the SQL injection attack might be designed to steal data rather than damage it. An attacker might figure how to get your web site to deliver a bunch of credit card numbers in response to a nominal request to edit their profile.
Yes, unless the table contains user-sensitive and/or XSS-injected data. Then you've another problem to fix. Always sanitize on SQL injections during constructing SQL queries and always sanitize on XSS injections during displaying client-controlled data in HTML output.
Other people have noted that you've partially addressed the issue of data loss (restore from hopefully recent backup) but missed the issue of data theft.
There's another potential issue. Many SQL servers allow you to execute arbitrary system commands (e.g. MS SQL). Others (e.g. MySQL) let you write arbitrary files (see also this article on exploiting MySQL injections). The bottom line is that an SQL injection attack can compromise the whole system, and thence onward. Of course, there are configuration options to disable some of these, but they're real concerns.
If you want recommendations, I suggest PDO with prepared statements.