I'm new to PHP, and not yet familiar with how this works.
If I use mysqli_real_escape_string() and parameterize every variable in the SQL query, can I spare myself doing the validation with is_numeric(), etc.?
What is the best way to create a injection detection system? Simply validate the user's input with regex stuff and save it in the database?
Parametrizing your query is enough, you don't need anything else. You'll input the stuff they "inject" als a string, and there is nothing especially wrong with sql in a database... I suspect SO's database is full of SQL ;)
Escaping a value for MySQL simply adds a backslash in front of of the following characters: NULL \n \r \ ' " and 0x1A. It does nothing else.
An "escaped" value isn't magically safe for use in SQL. Escaping prevents special characters (such as quotes) from being misinterpreted. But if you insert an escaped value into an SQL query without surrounding it in quotes, then you've completely missed the point, and you are no more safe than you would have otherwise been.
Remember, the security procedure is quote and escape. You should always use those two together, since neither is safe without the other.
Also, if you can absolutely guarantee that your input value contains none of the above characters, then you also can be certain that your escaped string will always be identical to the unescaped one, and therefore escaping serves no additional purpose under those conditions.
But More Importantly:
Finally we have, in retrospect, realized that SQL was poorly designed from a security perspective, and relying on users properly quote and escape their data is just a really bad idea.
Parameterized queries are the solution, since it safely separates the data from the control structure. Parameterized queries are possible with mysqli by using prepare() followed by bind_param(). No escaping is necessary when using this method, and you can be confident that you are absolutely immune from SQL injection attacks.
Even if you have protected your variables against injection by using a parameterized query or mysql_real_escape_string() (not mysql_escape_string()), you should still validate them on the server side to ensure that they match the expected type of input. That way, if they do not, you can return an error message to your user with a request to retry those form fields.
If you use a parameterized query, such as offered by MySQLi as prepared statements, you needn't also escape the strings. However, if you don't use a parameterized query, it is essential to call mysql_real_escape_string() on every input parameter received by PHP.
This is a good question, and I think one of the best ways to avoid SQL injection is to learn about proper use of prepared statements
These will really help out the security of your application.
The issue with sql injection is the user inserting SQL data into a command and not validating that the data meets your business rules.
Making sure all user data is passed through mysqli_real_escape_string or used prepared statements is the best way to avoid problems.
Related
Using the pg_escape_literal PHP function, I'm escaping my user input data as follows:
<?php
$dbconn = pg_connect('dbname=foo');
$escaped = pg_escape_literal($_GET['name']);
pg_query("INSERT INTO participants (name) VALUES ({$escaped})");
?>
Being new to PostgreSQL, my questions are:
Is there a way to achieve an SQL injection given this code?
Is there any other vulnerability that is left untreated in this code?
Using PHP 5.4 and PostgreSQL 9.2.
Since you do not trust any user input and you escape it accordingly, there is no injection in there.
Furthermore, you can use prepared statements to ensure you don't forget any escape, and you take correct data types for the sentence.
Remember that if you forget only 1 escape, your whole system is compromised despite it may be escaped all the rest.
That is the recomended method for escaping queries and ensuring sql injection attacks do not work.
If you are extra paranoid, or just want to be safe, you can also do regex to weed out unwanted characters and length checks of the data before you escape it.
I'm using PHP PDO for my queries, everywhere, but I read that in very rare cases there could still be "second order injections" where an unsafe variable is stored then executed when used in another statement.
Will prepared statements still protect against this? As long as I make sure I always use them? Or do I have to take more precautions? Am I still vulnerable to XSS attacks?
I also have a couple more questions, just out of curiosity, if you all don't mind:
Is it possible to have an SQL Injection with only alphanumeric characters, spaces, and one dash? Like select * from something where name='$some_variable'. All the examples I've seen seem to require other characters like semicolons, quotes, or double dashes.
I've read many SQL examples where the unsafe variable could be set to form another statement, eg
$foo = "foo'); INSERT INTO users (name) VALUES ('hi";
$bar = ("INSERT INTO users (name) VALUES ('$foo')");
But I just tested and mysql_query doesn't even allow multiple statements. I know you can still have injections within 1 statement, but can I confirm that you won't have problems with multiple statements in PHP?
Not to beat a dead (or is it a very alive?) horse, but...
Injection can only happen when data is read by the SQL engine as commands. In a very simple case, if you allow unescaped " characters in your data, and your data is encapsulated by " characters in SQL, they you have enabled an SQL injection attack.
The key to preventing any SQL injection is to properly validate and escape incoming data EVERY time, at the time it goes into the SQL statement. An easy way to do this is to just use prepared statements, which take care of it for you, allowing you to safely pass parameters to an SQL statement.
Each database library has it's own way of escaping or using prepared statements. In MySQL and PHP, you have mysqli_real_escape_string(), which should be used EVERY TIME PERIOD, when you are using the mysqli library.
The PDO library has it's own way, but if I recall correctly, prepared statements were a big part of PDO -- use them 100% of the time, and you will be OK in that regard.
To prevent agains XSS attacks, use HTML Purifier, and never strip_tags(), see links below for more info, PDO prepared statements should be fine for SQL Injection prevention:
http://www.reddit.com/r/PHP/comments/nj5t0/what_everyone_should_know_about_strip_tags/
http://htmlpurifier.org/
Possible Duplicate:
SQL injection that gets around mysql_real_escape_string()
I havent seen any valuabe or not outdated info on this.
So, there is this question: Does mysql_real_escape_string() FULLY protect against SQL injection? Yet it is very outdated(its from '09), so as of php 5.3 and mysql 5.5 in '12, does it protect fully ?
mysql_real_escape_string ALONE can prevent nothing.
Moreover, this function has nothing to do with injections at all.
Whenever you need escaping, you need it despite of "security", but just because it is required by SQL syntax. And where you don't need it, escaping won't help you even a bit.
The usage of this function is simple: when you have to use a quoted string in the query, you have to escape it's contents. Not because of some imaginary "malicious users", but merely to escape these quotes that were used to delimit a string. This is extremely simple rule, yet extremely mistaken by PHP folks.
This is just syntax related function, not security related.
Depending on this function in security matters, believing that it will "secure your database against malicious users" WILL lead you to injection.
A conclusion that you can make yourself:
No, this function is not enough.
Prepared statements is not a silver bullet too. It covers your back for only half of possible cases. See the important addition I made to the famous question for the details
long time since I read a blog post about this so it may no longer hold true BUT...
The posts stated that if you had unicode encoded characters in your string they would be missed by real escape string but would be evaluated by mysql engine - alluding to the idea that you could indeed still be open to a well placed injection.
I can't remember the blog post but this question on here is in the same ball-park.
Yes. By properly escaping the string using the native mysql escape functions, it's not possible to "break out" and execute a query.
However, a better approach would be to use prepared statements. This will do a number of things. By using prepared statements you take advantage of even more optimization from the database and it will properly escape any data passed in. Take a look at: http://php.net/manual/en/mysqli.prepare.php
I've read in several places that htmlspecialchars is not enough to prevent SQL injection attacks. I'm working with a legacy codebase and it uses this to sanitize user input:
stripslashes(htmlspecialchars(trim($value), ENT_QUOTES, 'UTF-8'))
My gut tells me that this is also unsafe but my coworker insists that it is. I don't have much experience in working with plain PHP so could someone please tell me why this is unsafe so that I can convince my coworker to use something better?
I've read in several places that htmlspecialchars is not enough to prevent SQL injection attacks
It protects against XSS attacks, but SQL is not HTML so it does nothing for SQL injection.
(You should move the htmlspecialchars encoding to "before inserting into HTML" instead of "before inserting into SQL")
My gut tells me that this is also unsafe but my coworker insists that it is.
Your gut is right. The fact it leaves quote characters alone shouts unsafe!.
Take a look at Bobby Tables. It demonstrates the problem and provides a number of solutions. Anything that uses bound parameters is good.
Use prepared statements.
disable magic quote in php.ini and use PDO. bum
htmlspecialchars to escape params in SQL is the ugliest
It may prevent you from XSS, but not from SQLi, because it doesn't quote any SQL-specific (or DBMS-specific) special characters. The most modern solution is to use PDO with Prepared Statement or PDO:quote(). Legacy solutions cover mysql_escape_string() and such. Refer the manual about the db-driver you are using, about the features it provides to prevent you from SQLi.
You should be calling a database specific escaping function on things you insert into queries.
For a MYSQL database, use mysql_real_escape_string.
It depends on the type of SQL query it is injecting. SQL injections in string fields (enclosed with ' and ") can be disabled by encoding or removing this characters. But in general this is not the solution!
You should NEVER EVER concatenate the SQL string together and send it to the database, especially if it contains user supplied data. You should always use the prepare statement to prepare a SQL statement with placeholders and then pass the parameters separately. Yes, this means that you will probably need to have more than one line of code and you will call corresponding SQL functions.
This is the only good solution for this that is implemented in all programming languages.
mysql_real_escape_string would be better than mysql_escape_string as it has been deprecated.
On the PDO::Prepare page it states,
"and helps to prevent SQL injection attacks by eliminating the need to manually quote the parameters"
Knowing this, is there a PHP function like mysql_real_escape_string() that takes care of escaping stings for PDO? Or does PDO take care of all escaping for me?
EDIT
I realize now that I asked the wrong question. My question really was, "What all does PDO take care of for me?" Which I realize now with these answers that it really only removes the need to escape the quotes. But I would still need to do any other PHP sanitize calls on the values that I pass to the execute function. Such as htmlentities(), strip_tags()...etc...
PDO does not escape the variables. The variables and the SQL command are transferred independently over the MySQL connection. And the SQL tokenizer (parser) never looks at the values. Values are just copied verbatim into the database storage without the possibility of ever causing any harm. That's why there is no need to marshall the data with prepared statements.
Note that this is mostly a speed advantage. With mysql_real_escape_string() you first marshall your variables in PHP, then send an inefficient SQL command to the server, which has to costly segregate the actual SQL command from the values again. That's why it's often said that the security advantage is only implicit, not the primary reason for using PDO.
If you concat the SQL command and don't actually use prepared statments (not good!), then yes, there still is an escape function for PDO: $pdo->quote($string)
Very few people here understand what escaping is and when to use it.
Escaping itself does not make any data "safe". It just escapes delimiters, to distinguish a delimiter from a part of data. field = 'it's me' will cause an error, while field = 'it\'s me' will not. That's the only purpose of escaping. So, it works only when you use quotes. If you don't - escaping becomes useless.
Do you use quotes with placeholders? No. Thus, no escaping would be sensible.
When you are binding your variables, it works a very different way: it does not send the whole query to the server, but sends your prepared query separated from the bound data. So it cannot interfere. And thus makes no injection possible.
Yes and no:
Literals which you embed into the statement string need to be escaped as normal.
Values which you bind to the prepared statement are handled by the library.
If you prepare a statement and use bindParam or bindValue to supply variables, you do not need to escape the variables. Note that these functions assume that the variable contains a string, so use the third parameter to bindValue if you want to use booleans or floats.
You don't have to worry about it. PDO does not require you to escape your data before passing it along to the database.
Edit: Just to be clear, I mean to say that as long as you are passing variables into your parameters (for example, the value of a form field), you don't have to worry about it. However, if you're passing variables that you've defined as strings, for example, then obviously you need to escape anything that needs escaping in that string in order to avoid breaking syntax. However, this wouldn't even make much sense since one of the main advantages of PDO is that you're passing information from the user to the database without having to sanitize it yourself, and there aren't many times (if any?) that you would be passing strings that you yourself had defined.
Also, make sure you still sanitize your data for type. For example, make sure it's an integer if you expect it to be, make sure it's less than or greater than x if you expect it to be, etc.