I'm learning about avoiding SQL injections and I'm a bit confused.
When using bind_param, I don't understand the purpose. On the manual page, I found this example:
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
Now, assuming those 4 variables were user-inputted, I don't understand how this prevents SQL injections. By my understanding, they can still input whatever they want in there.
I also can't find an explanation for the 'sssd' in there. What does it do? Is that what makes it secure-er?
Final question: I read on another question that mysqli_real_escape_string is deprecated, but it doesn't say that in the manual. How is it deprecated? Can it not escape special characters anymore for some reason?
Note: This question explained what bind_param does, but I still don't understand why it is any safer or more protected.
Bind_param explanation
Now, assuming those 4 variables were user-inputted, I don't understand
how this prevents SQL injections. By my understanding, they can still
input whatever they want in there.
The main principle there is using prepared statement which is designed for sending safe query to db server, this can be done by escaping user input which is not part of the real query, and also checking the query without any (where clause) to check the validity of the query before using any parameters.
From this question: PDO sends raw query to MySQL while Mysqli sends prepared query, both produce the same result
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username =?")) {
$stmt->bind_param("i", $user);
$user = "''1''";
server logs:
130802 23:39:39 175 Connect ****#localhost on testdb
175 Prepare SELECT * FROM users WHERE username =?
175 Execute SELECT * FROM users WHERE username =0
175 Quit
By Using prepared statement, db server will check the query without any parameter, at this stage, errors can be detected before binding any parameter, then, if the query was valid, parameters also will be send to the server for finalizing the query.
From PHP Manual http://php.net/manual/en/mysqli.quickstart.prepared-statements.php:
Escaping and SQL injection
Bound variables will be escaped automatically by the server. The
server inserts their escaped values at the appropriate places into the
statement template before execution. A hint must be provided to the
server for the type of bound variable, to create an appropriate
conversion. See the mysqli_stmt_bind_param() function for more
information.
..
I also can't find an explanation for the 'sssd' in there. What does it
do? Is that what makes it secure-er?
The answer is here: http://php.net/manual/en/mysqli-stmt.bind-param.php
i
corresponding variable has type integer
d
corresponding variable has type double
s
corresponding variable has type string
b
corresponding variable is a blob and will be sent in packets
Final question: I read on another question that
mysqli_real_escape_string is deprecated, but it doesn't say that in
the manual. How is it deprecated? Can it not escape special characters
anymore for some reason?
Can you give a reference? I think you misunderstood with (mysql_real_escape_string())
By using prepared statements you are separating SQL queries from user entered data. Instead of input data, you put placeholders ('?' char) in your SQL query. Then you send the query to the DBMS server (e.g.: MySQL) by means of the "mysqli::prepare" method. So the server checks that everything is ok and, if so, it waits for input data. By now it already knows your query. Just it has to wait for input data to bind to the query.
At this point, "bind_param" comes into action, binding placeholders to user entered data.
Notice that bind_param only binds data to placeholders leaving unchanged the query.
So there is not way to change the original SQL query, because it has already sent to the server by means of the prepare method and because you are sending SQL queries and input data separately so user entered data can't interfere with queries.
ANYWAY...
The actual purpose to use a prepared statement in SQL is to cut the cost of processing queries, NOT to separate data from query. That's how it's being used now, not how it was designed to be used in the first place.
'sssd' stands for "string", "string", "string" and "double".
In fact: $code is a string, $language is a string, $official is a string and $percent is a double type.
mysqli_real_escape_string is not deprecated but mysql_real_escape_string is deprecated
(the first one is mysqlI, where I stands for "improved").
Related
I am trying to understand when I should use prepared statements in php/mysqli. Should every php/mysqli query use prepared statements or just queries and instances where user input is involved ... such as an html form that asks a user to enter data to search within a database?
I am migrating my old php5/mysql code to php7/mysqli. I have many php files that query a mysql db. I would like clarification if I need to use prepared statements for every php file that connects to a mysql db ... for example php files that are referenced via "php require" and include simple sql select statements to render images and links to a html page?
<?php
//establish connection
$con = new mysqli('localhost','uid','pw','db');
//check connection
if ($con->connect_error) {
die("Connection failed: " . $con->connect_error);
}
//search variable that stores user input
$search = "%{$_POST['search']}%";
//prepare, bind and fetch
$stmt = $con->prepare("SELECT image, caption FROM `tblimages`
WHERE catid = 3 AND caption LIKE ? order by caption ASC");
$stmt->bind_param("s", $search);
$stmt->execute();
$stmt->bind_result($image,$caption);
while ($stmt->fetch()) {
echo "{$image} <br> {$caption} <br>";
}
$stmt->close();
//close database connection
mysqli_close($con);
?>
The code above works and is the first I've ever used prepared statements. It takes user input from a form (blank box to enter a search term - POST) and searches a db ... then renders results to an html page. This seems like a logical use of prepared statements. However ... I have other php files where users select data from a drop down box in a form to render a result (the user does not enter data into a search box like above). Do I use prepared statements for that instance as well? Plus do I use prepared statements for php files that are referenced via "php require" and include simple sql select statements to render images and links to a html page? I've yet to find clarification of the specific instances to use prepared statements to prevent sql injections. Any clarification or references welcome.
Short answer: Always use prepared statements.
Long answer:
Prepared statements separate your data from SQL commands. They are provided by PDO or by MySQLi. Their biggest advantage is that it is impossible to have SQL injection if your data is treated as data. Another advantage is that you can execute the same query over and over again with different set of data, which might be better for your performance and often keeps your code cleaner.
However, there are times when you would like to have some kind of dynamic query based on user's selection or actions. As you probably know table and column names are not data, but part of SQL query, therefore you can't keep them separated. The alternative to prepared statements then is to have a white list of possible values and only allow user input validated against the white list.
You might ask what are query, real_query, multi_query and PDO::exec good for?
As the PHP Manual shows they are good at times when you only need to execute constant query without any variables or when you have a query which can't be prepared. e.g.
$mysqli->query('SELECT Name FROM City LIMIT 10');
$pdo->exec('DELETE FROM fruit');
$mysqli->multi_query('DELETE FROM fruit; DELETE FROM pets;');
What if you know the type and values of your data? Should you also prepare/bind?
Yes! Get into a habit of binding all data going with SQL query. There is no reason to make exceptions. It is much more difficult to trace those exceptions in your code and always be sure you do not overwrite the "safe" value with some unknown input.
If you are still not sure how to use prepared statements or you think that they are too complicated (they are not) you can take a look at an amazing PHP tutorial at https://phpdelusions.net
This is how MySQLi prepared statements work in PHP:
Prepare an SQL query with empty values as placeholders (with a question mark for each value).
Bind variables to the placeholders by stating each variable, along with its type.
Execute query.
The four variable types allowed:
i - Integer
d - Double
s - String
b - Blob
A prepared statement, as its name implies, is a way of preparing the MySQL call, without storing the variables. You tell it that variables will go there eventually — just not yet. The best way to demonstrate it is by example.
$stmt = $mysqli->prepare("SELECT * FROM myTable WHERE name = ? AND age = ?");
$stmt->bind_param("si", $_POST['name'], $_POST['age']);
$stmt->execute();
//fetching result would go here, but will be covered later
$stmt->close();
If you've never seen prepared statements before, this may look a little weird.
Basically what's happening is that you are creating a template for what the SQL statement will be.
In this case, we are selecting everything from myTable, where name and age equal ?. The question mark is just a placeholder for where the values will go.
The bind_param() method is where you attach variables to the dummy values in the prepared template.
Notice how there are two letters in quotes before the variables.
This tells the database the variable types.
The s specifies that name will be a string value, while the i forces age to be an integer.
This is precisely why I didn't add quotation marks around the question mark for name, like I normally would for a string in an SQL call.
You probably thought I just forgot to, but the reality is that there is simply no need to (In fact, it actually won't work if you do put quotes around the ?, since it will be treated as a string literal, rather than a dummy placeholder.).
You are already telling it that it will be a string literal when you call bind_param(), so even if a malicious user tries to insert SQL into your user inputs, it will still be treated as a string.
$stmt->execute() then actually runs the code; the last line simply closes the prepared statement. We will cover fetching results in the Select section.
Documents really only mentions:
mysqli::prepare -- mysqli_prepare — Prepare an SQL statement for execution
I want to know what actually happens under the hood after calling mysqli_prepare() with a sql statement.
Could anyone elaborate with that and also why couldn't it be skipped? Couldn't this be done internally in mysqlite3?
A reference would be appreciated.
The difference between execute() and prepare() is not that the prepare() method has some internal flag like "secure=true;" which will be set and magically you are save for SQL injections. In fact, you can have SQL injections with prepare() as well when you use it wrong:
$stmt = $db->prepare('SELECT password FROM user WHERE username = "'.$username.'"');
$stmt->execute();
// ...
The point of prepared statements is that the values/arguments/variables for the SQL query are send separated from the actual SQL query to the MySQL server. This way the values/arguments/variables cannot change the SQL query you are trying to send. This prevents SQL injections where the inputs contain values like "='' OR 1 = 1 --".
The prepared statement is building a data structure where you set the values for the prepared statement separated via the additional API calls like bind_param(). The SQL server will use the "prepared" statement and use the values received from bind_param(). The query has been read, analyzed, well, it has been "prepared", and is fixed now (for the duration of this prepared statement) before even the first value with the potential dangerous data has been read. The WHERE condition cannot be altered or weakened, another SQL query cannot be appended or other rows/columns/tables can be edited.
Because of this, you cannot just redirect the execute() call internally to prepare() to be safe, because then you are missing the bind_param() calls. That being said: Use execute() when you have a fixed SQL query without any variables and/or user inputs and use prepare() for prepared statements, where you have an SQL query which depends on variables and/or user inputs.
In very short and in terms all will understand, you will want to use prepared statement(aka mysqli_prepare) to block sql injections, so in other words for security reasons.
I have been researching into PDO's bindValue(). I know that preparing my SQL statements with PDO is keeping SQL injections from happening.
Code Example:
$stmt = $dbh->prepare('SELECT * FROM articles WHERE id = :id AND title = :title');
$stmt->bindValue(':id', PDO::PARAM_INT);
$stmt->bindValue(':title', PDO::PARAM_STR);
$stmt->execute();
By binding the ID as a number, and the Title was a string, we can limit the damage done when someone tries to do an SQL injection within the code.
Should we always bind our values with a PDO::PARAM_ so we can limit what can be pulled from the database in an SQL injection? Does this add more security with PDO when doing our bindValue()?
There are two questions in one. It is essential not to confuse them
Should we always use a placeholder to represent a variable data in the query?
Should we always use certain function in the application code to follow the above rule?
Also, from the clarification in the comments under the opening post, the third question can be seen:
Should we always use third parameter, or it's OK to let PDO bind all the parameters as strings by default?
1. For the first question the answer is absolutely and definitely - YES.
While for the second one, for sake of code sanity and DRYness -
2. Avoid manual binding when possible.
There are many ways to avoid manual binding. Some of them are:
ORM is an excellent solution for the simple CRUD operations and must have in a modern app. It will hide SQL from you completely, doing the binding behind the scenes:
$user = User::model()->findByPk($id);
Query Builder is also the way to go, disguising SQL in some PHP operators but again hiding the binding behind the scenes:
$user = $db->select('*')->from('users')->where('id = ?', $id)->fetch();
some abstraction library may take care of the passed data by means of type-hinted-placeholders, hiding the actual binding again:
$user = $db->getRow("SELECT * FROM users WHERE id =?i", $id);
if you are still using PHP in the last century ways, and have raw PDO all over the code - then you can pass your variables in execute(), still saving yourself a lot of typing:
$stmt = $dbh->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
$user = $stmt->fetch();
As of the third question - as long as you are binding numbers as strings (but not the opposite!) -
3. It's all right with mysql, to send almost every parameter as a string
as mysql will always convert your data to the proper type. The only case known to me, is a LIMIT clause where you cannot format number as a string - thus, the only related case is one when PDO is set in emulation mode and you have to pass a parameter in LIMIT clause. In all other cases you can omit third parameter, as well as explicit call to bindValue() without any problem.
You should definitely use the prepare API and pass values separately from the query, as opposed to doing plain string interpolation (e.g. "SELECT * FROM foo WHERE bar = '$baz'" → bad).
For binding parameters, you have three options:
bindParam
bindValue
execute
It doesn't really matter which of these you use, they're all equally secure. See these answers for some details about the differences:
Confusion between bindValue() and bindParam()?
Using PDO without binding
When using bindParam or bindValue, passing the third PDO::PARAM_ argument type is optional. If you don't pass it, it defaults to binding the argument as string. That means you may end up with a query equivalent to ... WHERE foo = '42' instead of ... WHERE foo = 42. It depends on your database how it will handle this. MySQL will cast the string to a number automatically as needed, just as PHP does (e.g. in '42' + 1). Other databases may be more fussy about types.
Again, all options are equally safe. If you're trying to bind a string 'foo' using PDO::PARAM_INT, the string will be cast to an integer and accordingly bound as the value 0. There's no possibility for injection.
Yes you should always bind params with prepared statement.
It's more secure, and limit SQL injection. But this is not the only think you must do to query params: a correct type control is required, best if you map a row into an object and throw an exception in it if it has invalid data.
I hope I can be useful!
Yes, binding is the way to go. Or parameterised queries which a more generalized term.
#Theo does a wonderful job explaining why parameterized queries is the way to go
You could also use stored procedures for additional security but is an over kill if you have one application to one database. Its good for multiple applications to one database to ensure consistency when handling data
In my MySQL table, I have a column of TEXT type. On my HTML Form, user pastes text into it that might contain "" , ' ( ) and so on. I want to know how to safely execute Insert Query if these characters exist in the text and might crash the query execution.
How to handle them properly in PHP?
If you are not using prepared statements (either with PDO or MySqli) you should pass user's input trough MySql_Real_Escape_String() function. Or MySqli_Real_Escape_String() if you are using MySqli (but not prepared statements).
I would, however, advise you to use prepared statements as your life will be much easier and you get SQL-Injection protection for free.
Use a prepared statement.
Prepared statements can help increase
security by separating SQL logic from
the data being supplied. This
separation of logic and data can help
prevent a very common type of
vulnerability called an SQL injection
attack. Normally when you are dealing
with an ad hoc query, you need to be
very careful when handling the data
that you received from the user. This
entails using functions that escape
all of the necessary trouble
characters, such as the single quote,
double quote, and backslash
characters. This is unnecessary when
dealing with prepared statements. The
separation of the data allows MySQL to
automatically take into account these
characters and they do not need to be
escaped using any special function.
A quick example,
$db = new mysqli('localhost', 'username', 'password', 'db');
$stmt = $db->prepare("INSERT INTO mytable (text_column) VALUES (?)");
$stmt->bind_param("s", $mytext); // s = string, b = boolean, i = int, etc
$stmt->execute();
...
Historically, I've always used
mysql_real_escape_string()
for all input derived from users that ends up touching the database.
Now that I've completely converted over to MySQLi and I'm using prepared queries with bound parameters, have I effectively eliminated the possibility of SQL injection attacks?
Am I correct in saying I no longer need
mysql_real_escape_string()?
This is my understanding and the basis of a project of mine:
http://sourceforge.net/projects/mysqldoneright/files/Base/MysqlDoneRight-0.23.tar.gz/download
This is not something I want to get wrong though as now that I've released it, it could affect others as well.
All user provided input will now end up in bind_parms.
The queries provided in the prepare phase are static.
Yes. Using the prepared query will escape parameters.
It's not so simple. You can use bound parameters instead of interpolating application variables into SQL expressions in place of literal values only:
$sql = "SELECT * FROM MyTable WHERE id = ".$_GET["id"]; // not safe
$sql = "SELECT * FROM MyTable WHERE id = ?"; // safe
But what if you need to make part of the query dynamic besides a literal value?
$sql = "SELECT * FROM MyTable ORDER BY ".$_GET["sortcolumn"]; // not safe
$sql = "SELECT * FROM MyTable ORDER BY ?"; // doesn't work!
The parameter will always be interpreted as a value, not a column identifier. You can run a query with ORDER BY 'score', which is different from ORDER BY score, and using a parameter will be interpreted as the former -- a constant string 'score', not the value in the column named score.
So there are lots of cases where you have to use dynamic SQL and interpolate application variables into the query to get the results you want. In those cases, query parameters can't help you. You still have to be vigilant and code defensively to prevent SQL injection flaws.
No framework or data-access library can do this work for you. You can always construct a SQL query string that contains a SQL injection flaw, and you do this before the data-access library sees the SQL query. So how is it supposed to know what's intentional and what's a flaw?
Here are the methods to achieve secure SQL queries:
Filter input. Trace any variable data that gets inserted into your SQL queries. Use input filters to strip out illegal characters. For instance, if you expect an integer, make sure the input is constrained to be an integer.
Escape output. Output in this context can be the SQL query which you send to the database server. You know you can use SQL query parameters for values, but what about a column name? You need an escaping/quoting function for identifiers, just like the old mysql_real_escape_string() is for string values.
Code reviews. Get someone to be a second pair of eyes and go over your SQL code, to help you spot places where you neglected to use the above two techniques.
When you bind parameters to a prepared statement, it escapes the data automatically, so you shouldn't escape it before you send it through. Double escaping is usually a bad thing. At the very least, it produces ugly results with extra escaped characters later on.