Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I've design this small function and I would like to know if anyone thinks it's safe enough, or if not, why.
function safeSQLI($INPUT){
// Trim un-needed spaces
$safe_input = trim($INPUT);
// Replace any SQL commands
$safe_input = str_ireplace("drop", "", $safe_input);
etc...
// Escape the result
$safe_input = mysql_real_escape_string($safe_input);
// Return the "Safe" result
return $safe_input;
}
Answer: No, it's not safe at all. I am now using PDO and I think I was missing something great before now.
str_ireplace() is generally a bad choice, because it doesn't work recursive. Try the following:
$safe_input = 'DELDELETEETE * FROM users';
Will result in:
DELETE * FROM users
So, your entire function falls back to mysql_real_escape_string() and everything that came before is useless. The point is: It's not impossible to write proper filtering methods, but it can be a real challenge to cover every single case there is.
You want to either follow a whitelisting approach and allow only certain types of content. This is tough to implement in the real world.
Or a blacklisting approach and deny certain characters. Most SQL injection vulnerabilites happen because one can inject additional commands in a string. If you escape the ' (or use mysql_real_escape_string(), you are usually safe). However, it depends on your web app if additional filtering is required or not.
Or use prepared statements.
It does prevent injection, provided you use quotes like you should:
SELECT * FROM `users` WHERE `name`='$username'
For example.
However it is complete overkill. mysql_real_escape_string is sufficient to make an input safe, provided you use the quotes as above.
I spent all day today trying to get some database work done on a server that had been locked down to return "Not Acceptable" HTTP responses if "anything that looked like a database table name was present in the request". Needless to say, it took significantly longer than it needed to, when a simple mysql_real_escape_string would have sufficed.
Not safe at all. Try running this:
echo safeSQLI("drdropop tatableble TABLE_NAME");
That never let you insert a post about SQL in your blog.
I think use prepare statements and mysql_real_escape_string is safe enough.
PS: And you can avoid DDL sentences at BD level, with permissions.
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.
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.
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 8 years ago.
I just had this idea of "preSecure" all userinput data from $_post and $_get. But I was wondering if this is good practice and would like some input on this. Here is what I came up with:
function clean_str($str){
return preg_replace('#[^a-z_ 0-9#.-]#i', '', $str);
}
if ($_POST){
foreach ($_POST AS $key => $val){
$_POST[$key] = clean_str($val);
}
}
if ($_GET){
foreach ($_GET AS $key => $val){
$_GET[$key] = clean_str($val);
}
}
This snippet would simply be run at the beginning of each http request. The clean_str function can be developed to allow other chars and replace characters etc (this is just an example). But I think the first goal are to simply prevent sql injection. The only bad thing I can see with this approach right now is if your "plugin" need to send sql commands from user input. The appraoch above could we wrapped in a function of course and be called if needed. Post and Get are global vars so that would not be a problem.
I'm actually writing my own framework (still a lot of work) that I will release if I ever be able to finish it. The thing is that I often see novice developers add $_POST['userinput'] inside database queries. The code above should make even that okay. Well that was some background of what I'm up to and why I bring this up.
I would be very happy to hear your thoughts. This might not be the best question for Stack Overflow, I suppose I want to open more like a discussion to this approach to share thoughts and inputs. But to formulate my question(s) to this, it would be something in line with: Are there any other approaches that would be faster or more scalable than this, or is equal to this, or can another function complement this approach? Is this approach good practice? Is it okay to overwrite the global vars of post and get data like above?
I know the code above is not object oriented, but it's about the approach of cleaning the users' input datas automatically before running checks on them. I think this will save a lot of code and headaches.
Please share your thoughts with me. As comments are limited here on Stack Overflow, I would appreciate if you reply as answers if you bring new thoughts to this table. Comments are to comment on specific thoughts/answers in this case.
First off if the user tries to inject an array then it will generate a notice, you should check for a string before calling it, else:
Notice: Array to string conversion
But to be honest, you are just creating your own version of magic quotes, which isn't a good idea.
The simple and better solution would be to use prepared statements, with PDO or MySQLi.
A post on the PHP Website for magic quote sums it up nicely:
The very reason magic quotes are deprecated is that a one-size-fits-all approach to escaping/quoting is wrongheaded and downright dangerous. Different types of content have different special chars and different ways of escaping them, and what works in one tends to have side effects elsewhere. Any sample code, here or anywhere else, that pretends to work like magic quotes --or does a similar conversion for HTML, SQL, or anything else for that matter -- is similarly wrongheaded and similarly dangerous.
Magic quotes are not for security. They never have been. It's a convenience thing -- they exist so a PHP noob can fumble along and eventually write some mysql queries that kinda work, without having to learn about escaping/quoting data properly. They prevent a few accidental syntax errors, as is their job. But they won't stop a malicious and semi-knowledgeable attacker from trashing the PHP noob's database. And that poor noob may never even know how or why his database is now gone, because magic quotes (or his spiffy "i'm gonna escape everything" function) gave him a false sense of security. He never had to learn how to really handle untrusted input.
Data should be escaped where you need it escaped, and for the domain in which it will be used. (mysql_real_escape_string -- NOT addslashes! -- for MySQL (and that's only unless you have a clue and use prepared statements), htmlentities or htmlspecialchars for HTML, etc.) Anything else is doomed to failure.
This is not a good approach. Preventing MySQL injection isn't just a matter of making sure certain characters are escaped -- there are still plenty of attacks you can do even if you try to sanitize this way. It seems like you're overcomplicating things, when you can use prepared statements and no longer worry about all the things you need to check for. http://www.php.net/manual/en/mysqli.prepare.php
This question already has answers here:
How to escape strings in SQL Server using PHP?
(14 answers)
Closed 9 years ago.
I can sanitize and validate my input as much as possible but that definitely doesn't cover everything and if I scrub hard enough, thoroughly enough, I will completely wipe away my input.
I realize there are a lot of posts out there about this topic but it seems like they always go back to PDO or Mysql (yes - even if someone posts about SQL Server, half the answers they receive suggest mysql_real_escape_string - crazy world). I cannot use either. Even as I type and the little "similar questions" appear on the right of my screen, I keep clicking on various links and nothing fully answers my question.
I am using SQL Server. I am using PHP 5.2.4. I cannot use PDO (because...? my boss said 'no' and that's enough reason).
Is there a way I could write a safe way to prepare my own query statements?
In the past, I have tried to build a statement like this in the PHP. (where $input_* variables are some form of user input or I pulled them out of something)
$query = "
declare #varID int
declare #var1 int
declare #var2 varchar(100)
set #varID = cast('$input_ID' as int)
set #var1 = cast('$input_var1' as int)
set #var2 = cast('$input_var2' as varchar(100))
update table_name_goes_here
set var1 = #var1,
var2 = #var2
where ID = #varID;
";
# $query is then executed
but that can be vulnerable, too... obviously.... And the last thing I do is remove all necessary punctuation (sometimes I know they will have no reason to use certain characters)
But there has to be some other option... right? And mssql_bind only works for stored procedures, which is a definite option but I'm not sure if I want to volunteer to expand my responsibilities to include maintenance in the actual database by making insert/update procedures.
I would say that "because the boss said 'no'" is a terrible reason. Tell him (her?) that he is wrong. I know little of PHP, but regardless of the language, the only foolproof way to prevent injection is through paramaterized queries, or stored procedures. If the only way to do that in PHP is to use PDO, then use PDO.
Here is your reasoning for using PDO: https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
http://msdn.microsoft.com/en-us/magazine/cc163917.aspx
And why is there any SQL in the code at all? It is much easier to maintain if it is in the database, generally in the form of stored procedures.
You haven't answered the question "How do you intent to talk to the MS SQL database if PDO isn't allowed", but I assume there are the mssql_* functions to be used.
These do not have an escaping function readymade, but it seems they offer you to use prepared statements - which will do the job.
Otherwise you would have the security-relevant task to create an escaping function yourself. The character replacement is not really complicated when you first look at it, and you might be lucky to only have to cover your exact use case with a defined encoding. So this might really be as easy as looking up in the MSSQL manual which characters in a string are not allowed as a simple character, and how to escape them.
Be alerted though that you might miss edge cases, and if you can avoid it, I'd rather use the prepared statement feature.
Update: I misread the manual, mssql_execute() only calls stored procedures, not prepared statements. Can't you store procedures? Would be an easy way out. But I'd like to know how you are supposed to talk to the database anyways.
Update2: I found a link in a comment on php.net for mssql_bind pointing back to an SO answer about escaping: How to escape strings in SQL Server using PHP?
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
This is a security question meant for PDO prepared statements. Using PDO I know that the risk of sql injection is virtually impossible and that the class handles all of that for you. Coming from using them mysql_* stack I always feel as if I'm not handling security issues well enough. I'm usually used to writing hundreds of lines of code just to deal with security while now I'm literally just writing queries.
Is there really any security threats with PDO statements that I have to worry about other than length of the string in the db?
Definitely yes.
As a matter of fact, native prepared statements are good for simple schoolbook cases only.
Means you still have to write some "hundreds of lines" for whatever complex cases. I made a small digest of such cases in the PDO tag wiki. Main disadvantages are
no placeholders for identifiers. You have to format and inject them manually like in old good mysql_* code.
no placeholders for arrays. Means you still have to write some code manually and later inject it in the query - so, there is still a possibility to slip into some trouble.
Therefore you need a higher level of abstraction even upon PDO. A common solution is to use some sort of Query Builder which offered by every modern framework.
But personally I hate query builders as they seems too bloated to me, pretending to replace whole SQL but obviously failing with it. So, I don't understand why use SQL written in PHP when I can use pure SQL. For this purpose I created an abstraction library of mine, to correct all the disadvantages of native prepared statements, safeMysql. It has placeholders for everything you need and thus makes queries much safer than PDO, yet it makes application code dramatically shorter.
Means with safeMysql you indeed can "just literally write queries":
$sql = "SELECT * FROM articles WHERE id IN(?a) ORDER BY ?n LIMIT ?i"
$data = $db->getAll($sql, $ids,$_GET['order'], $limit);
$sql = "INSERT INTO stats SET pid=?i,ip=inet_aton(?s),?u ON DUPLICATE KEY UPDATE ?u";
$db->query($sql, $pid, $ip, $data, $data);
Just compare these 2-liners with amount of code you will need to write using raw PDO.
I think the answer is pretty close to yes for "sql injection attacks".
mysqli prepared statements and mysqli_real_escape_string
There are still many other types of attacks, but at least all your values are escaped.
Relying on PDO to "fix" your security is like relying on a compiler to find your bugs.