Do prepare statements secure your database? - php

I know that this question may be closed by some of you, but my question came up from you and your answers. I am reading the past two hours questions and answers for SQL Injections and how to protect your database. The same comes to the huge amount of webpages and tutorials I saw.
I found out that half of the people claim that prepare statements do secure your db, and the other 50 claim that it is not.
On the other hand, I read that mysql_real_escape_string does the job, and other people saying that it is not.
My question is who to believe ?
In addition, is this a proper prepare statement?
$stmt = $dbh->prepare("SELECT phpro_user_id, phpro_username, phpro_password FROM phpro_users
WHERE phpro_username = :phpro_username AND phpro_password = :phpro_password");
/*** bind the parameters ***/
$stmt->bindParam(':phpro_username', $phpro_username, PDO::PARAM_STR);
$stmt->bindParam(':phpro_password', $phpro_password, PDO::PARAM_STR, 40);
/*** execute the prepared statement ***/
$stmt->execute();

Both. Prepared statements will protect you against SQL injections if, and only if, you use them in a correct manner. Just' using' prepared statements won't help if you're still interpolating variables for table/column names for example.
$stmt = "SELECT * FROM $table WHERE $column = ?"; //not good...

Prepared statements don't. Bound parameters secure the statement (not the database as a whole) so long as all your untrusted data is passed via a parameter rather than being interpolated into the statement. When people use prepared statements, they almost always use bound parameters too, so the two names are often conflated.
Prepare statement
Run statement with variables as additional arguments
mysql_real_escape_string almost always does the job, but since it adds additional steps to the process, it is more prone to human error.
Escape each variable
Concatenate variables into SQL statement
Run statement

This is a good discussion. Your question assumes there is one technique that will "secure your database". In fact, there is no single technique that is best for all cases. So you need to learn to use multiple solutions in different situations.
Escaping literal values
Parameter placeholders in prepared queries
Whitelist maps
See my presentation SQL Injection Myths and Fallacies where I give details on everything you need to know to defend against SQL injection.
I also cover SQL injection in my book, SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming.

There are certain instances when prepared statements cannot be used. For example, when you must dynamically generate the contents of an IN() clause, you cannot do WHERE col IN (?) if you have dynamically chosen the comma-separated values to go into the IN(). Also, if you need to dynamically generate the columns list in your SELECT clause, you must do it by building up the SQL string.
Bottom line is, both have their place. Prepared statements are excellent for predetermined queries, or queries that must be executed multiple times. Escaped dynamic SQL is excellent when 1) you must have maximum flexibility and 2) you don't forget to escape all your input.

Related

How do I make a prepared statement for simple view? [duplicate]

Originally I used mysql_connect and mysql_query to do things. Then I learned of SQL injection, so I am trying to learn how to use prepared statements. I understand how the prepare and execute functions of the PDO class are useful to prevent SQL injection.
Are prepared statements only necessary when a users input is stored into a database? Would it be okay to still use mysql_num_rows, since I don't really run the risk of being hacked into by using this function? Or is it more secure to use prepared statements to do this? Should I use prepared statements for everything that involves using MySQL? Why?
tl/dr
Always. 100% of the time, use it. Always; and even if you don't need to use it. USE IT STILL.
mysql_* functions are deprecated. (Notice the big red box?)
Warning This extension was deprecated in PHP 5.5.0, and it was removed
in PHP 7.0.0. Instead, the MySQLi or PDO_MySQL extension should be
used. See also MySQL: choosing an API guide and related FAQ for more
information. Alternatives to this function include:
mysqli_connect()
PDO::__construct()
You'd be better off using PDO or MySQLi. Either of those 2 will suffice as compatible libraries when using prepared statements.
Trusting user input without prepared statements/sanitizing it is like leaving your car in a bad neighborhood, unlocked and with the keys in the ignition. You're basically saying, just come on in and take my goodies
You should never, and I mean never, trust user input. Unless you want this:
In reference to the data and storing it, as stated in the comments, you can never and should never trust any user related input. Unless you are 101% sure the data being used to manipulate said databases/values is hard-coded into your app, you must use prepared statements.
Now onto why you should use prepared statements. It's simple. To prevent SQL Injection, but in the most straight forward way possible. The way prepared statements work is simple, it sends the query and the data together, but seperate (if that makes sense haha) - What I mean is this:
Prepared Statements
Query: SELECT foo FROM bar WHERE foo = ?
Data: [? = 'a value here']
Compared to its predecessor, where you truncated a query with the data, sending it as a whole - in turn, meaning it was executed as a single transaction - causing SQL Injection vulnerabilities.
And here is a pseudo PHP PDO example to show you the simplicity of prepared statements/binds.
$dbh = PDO(....); // dsn in there mmm yeahh
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
Taken from PHP Manual for PDO Prepared Statements
More Reading
How can I prevent SQL-injection in php?
What is SQL-injection? (Simple Terms)
TL;DR Use prepared statements 100% of the time if your SQL makes use of data or input of any kind
You seem to have a slight confusion. First, please don't use mysql_*; the mysql_* functions are outdated, deprecated, and insecure. Use MySQLi or PDO instead. Second, mysql_num_rows has nothing to do with prepared statements and is not a PDO feature, anyway. You prepare the statement before you run the query, not after it when you want to count rows.
As for when to prepare statements, #Mike'Pomax'Kamermans nailed it in the comments. If you ever, even once, use any data that has ever been touched by a user -- even a supposedly trusted user -- or is generated by any kind of third party or third-party application, including a browser, use prepared statements. Only if 100% of your data is hard-coded can you trust it.
For example, you cannot trust:
Usernames
Passwords
Email addresses
User comments
Phone numbers
Dates
Search strings
Browser client strings
Credit card numbers
File names for uploads
And any other kind of input created by a user or that a user could manipulate.
You should validate all of these (for example, check that an email address is really an email address) before putting them in a database, of course. But even then, using prepared statements is the safe way to go.
There is a two solution for this-
01- Use Prepared Statements
To prevent SQL injections we will have to use something called prepared statements which uses bound parameters. Prepared Statements do not combine variables with SQL strings, so it is not possible for an attacker to modify the SQL statement. Prepared Statements combine the variable with the compiled SQL statement, this means that the SQL and the variables are sent separately and the variables are just interpreted as strings, not part of the SQL statement.
02- Prepared Statements with mySQLi.
Using the methods in the steps below, you will not need to use any other SQL injection filtering techniques such as mysql_real_escape_string(). This is because with prepared statements it is not possible to do conventional SQL injection.
eg -
$name = $_GET['username'];
if ($stmt = $mysqli->prepare("SELECT password FROM tbl_users WHERE name=?")) {
// Bind a variable to the parameter as a string.
$stmt->bind_param("s", $name);
// Execute the statement.
$stmt->execute();
// Get the variables from the query.
$stmt->bind_result($pass);
// Fetch the data.
$stmt->fetch();
// Display the data.
printf("Password for user %s is %s\n", $name, $pass);
// Close the prepared statement.
$stmt->close();
}
You can find more about this form - http://www.wikihow.com/Prevent-SQL-Injection-in-PHP
Mysql_* already has been deprecated so better to switch mysqli_* or PDO
For prevent sql injection (mysql) :- How can I prevent SQL injection in PHP?.
And prepared statements(These are SQL statements that are sent to and parsed by the database server separately from any parameters. ) use on your every user generated query data.
like on posting data you matching/getting records to db with query. so mean when you fire a query with form data.

Do I need to escape my variables if I use MySQLi prepared statements?

If I use MySQLi prepared statements like below:
$stmt = $con1->prepare("UPDATE Login SET Session='LoggedOut' where Session=?");
$stmt->bind_param('s',$Session);
$stmt->execute();
$stmt->close();
Do I still need to escape my variables like $Session with mysqli_real_escape_string(); like below:
$Session = mysqli_real_escape_string($con1, $_COOKIE['Session']);
$stmt = $con1->prepare("UPDATE Login SET Session='LoggedOut' where Session=?");
$stmt->bind_param('s',$Session);
$stmt->execute();
$stmt->close();
No, if you use prepared statements everywhere in your application you are safe from SQL injection. However, an important "gotcha" is 2nd order injection attacks which happen when some queries use prepared statements and others don't.
According to this answer of a similar question on SO:
prepared statements / parameterized queries are sufficient to prevent 1st order injection on that statement. If you use un-checked dynamic sql anywhere else in your application you are still vulnerable to 2nd order injection.
In summary, prepared statements create a separation between the data being sent and the SQL query itself, ensuring that the data can not be misinterpreted as the SQL query. However, an attacker can still enter SQL as data, and although it will not be executed when it is first stored if you are using prepared statements, you must still use caution when retrieving said results. Prepared statements protect your application in that particular place, but because SQL is still allowed to be stored in the database, your application is unsafe if you're later using that data without parameterization.
Nope you don't.
This is the only answer you need.
All the muddled talk in the other answer is just irrelevant. The guy is trying to tell you that if you are foolish enough not to use prepared statements all over the place, then you're in danger. Which is quite obvious, and irrelevant to a prepared statement itself.

Why do prepared statements protect against injections?

I've come os far as to gaining basic understanding of prepared statements and I get that they prevent SQL-injection attacks. But I have yet to understand WHY they protect against said attacks. I know there are similar questions asked but I didn't find the answers entirely satisfying.
Example - very unsafe code
So here we have the most basic way to communicate with our database:
$query = "SELECT * FROM users where id=$username";
Without any protection, a user can input malicious code and thus "trick" the database engine to execute a devastating query:
$username = "1; DROP TABLE users;"
SELECT * FROM users where id=1; DROP TABLE users;
What I don't understand is how a prepared statement manages to "filter out" such data. What is the mechanic behind it that does NOT lure the database to generate such a SQL-query as shown above? Is just as simple as escaping certain characters, like semicolon in the example above, or is it more complicated?
If I was to do the exact injection attack as in the example, but running it through a prepared statement, what kind of command string would reach the database engine?
Prepared statements don't just add in the text, they send it as data, and let the database process it separately. Because in reality the database doesn't actually use the SQL statements, it uses "compiled" versions of them.
Not quite sure I was clear, but it lies in how the query is sent to the database.
Prepared statements are usually built to use parameter binding. It's really the parameter binding that insulates against these kinds of attacks. You can use parameter binding without using prepared statements.
The second level of protection that prepared statements offer is that each is a single statement (so the use of ; to create two statements out of one won't work).
As a general rule, in order to be safe from injection attacks, the prepared statement must be prepared from data that is not derived from any external input.
Basically, if you use standard untyped parameter binding, you will get
SELECT * FROM users where id='1; DROP TABLE users;'
Which will error out on the Database, but will do no harm.
Please understand, that this is not the sam thing as running
SELECT * FROM users where id='$username'
with a suitably escaped $username - it happens on a lower layer of your DB access stack.

prepared statements - are they necessary

Prepared statments add a significant amount of code...yet I keep hearing mentions to use them...what value is added by going from 1 line of code to about 6? Is this simply to protect against sql injection?
Similar post here.
php.net on prepared statements here
Prepared statements offer excellent protection against SQL injection.
In addition to SQL injection protection, prepared statements offer reduced load on the database server when the same query is to executed multiple times, such as in an INSERT loop. The statement is only compiled once by the RDBMS rather than needing to be compiled each time as it would in a mysql_query() call.
Different APIs require varying amounts of code to execute a prepared statement. I find that PDO can be a little less verbose than MySQLi, if for example your situation permits the use of implicit parameter binding inside the execute() call. This only works, if all your params can be evaluated as strings though.
// PDO implicit binding example:
// Not many lines of code if the situation allows for it
$stmt = $pdo->prepare("SELECT * FROM tbl WHERE col1=? AND col2=? AND col3=?");
$stmt->execute(array($val1, $val2, $val3));
It's not fair to say that prepared statements cause 1 line of code to explode to 6. Actually, to use one you need just 2 lines: one to prepare the statement, and one to bind the parameters. Any other code you write (execute query, bind results, fetch results, etc.) would also be needed even if you didn't use prepared statements.
So in essence we are talking about what one additional line of code buys you. It buys you two things:
Protection against sql injections (which also includes protection against non-malicious malformed queries, e.g. preventing your query from breaking if an injected variable contains a single quote)
Possible performance benefits, if you end up executing the same prepared statement for different injected values.
Point #2 may not always apply, but consider that point #1 also saves you the necessary trouble of manually escaping the values to be injected in your query. This would be additional code (even if you can do it inline on the same line) that you would need to write yourself if not using prepared statements.
As I see things, we can conclude that with prepared statements you end up getting security and possibly performance for free.

mysqli prepared statements and mysqli_real_escape_string [duplicate]

This question already has an answer here:
Is mysql_real_escape_string() necessary when using prepared statements?
(1 answer)
Closed 3 months ago.
I'm currently using the mysqli php extension.
Traditionally I have used mysqli_real_escape_string to escape user input. However I am looking at changing over the code (hopefully in as few steps as possible) to use prepared statements.
I want to be clear on this - provided I use prepared statements to bind all of my variables, can I be confident that sql injection is impossible? (And dispense completely with mysqli_real_escape_string?)
Thanks
If you correctly bind all your variables you can dramatically reduce the risk of SQL injection. It is still possible to get an SQL injection if you create SQL dynamically for example:
'SELECT * FROM ' . $tablename . ' WHERE id = ?'
But if you avoid things like this it is unlikely you will have problems.
Speaking of security, there is no difference between both methods, if you correctly bind or format your variables.
Binding is just simpler, because it can be used just for any case, while escaping can't (so, you have to cast some variables instead of escaping/quoting).
Also, bear in mind that no binding nor escaping can make identifier safe. So, if you have to use a field name or operator in your query, you have to use a value, hardcoded in your script.
Here's my high-level view on the topic.
When using dynamic SQL strings, you are relying on the escaping function working correctly. Unfortunately, this is not always the case, as can be seen in this (admittedly old) example:
http://dev.mysql.com/doc/refman/5.0/en/news-5-0-22.html
Once your data values have been escaped, the SQL string has to be parsed and compiled by the database server. If the escaping function has not done its job properly, or a clever new SQL injection attack has been discovered, there is a chance that the server will mistake data for SQL statements.
If you use prepared statements with parameters, the statement is first parsed and compiled. The data values are combined with the compiled statement when it is executed. This separates the SQL logic from the data values - the opportunity to confuse the two should never occur.
So, yes, you can dispense with mysqli_real_escape_string, but I would not go so far as to say that using prepared statements with parameters makes SQL injection impossible. It makes it significantly harder, but as with the mysqli_real_escape_string bug, I guess there's always the chance that a yet to be discovered (or newly created) bug will make the seemingly impossible, possible.

Categories