Everyone knows that PDO prepare statement helps us prevent SQL injection attack. How about this:
function userQuery($username){
$mysqli->multi_query("
PREPARE stmt1 FROM 'SELECT * FROM user WHERE username=?';
SET #a = '$username';
EXECUTE stmt1 USING #a
");
}
userQuery('Kelvin');
Is this as safe as mysqli or PDO prepare statement?
I'm asking this question because I found these sentences on wiki:
Prepared statements are resilient against SQL injection, because parameter values, which are transmitted later using a different protocol, need not be correctly escaped. If the original statement template is not derived from external input, SQL injection cannot occur.
They mention about parameters are transmitted later with different protocol. And I don't really understand
this.
How can parameters are transmitted later with different protocol prevent injection attack?
[I assume that you meant $mysqli is mysqli connection.]
Although the execution of stmt1 (the last of your three queries) is safe, the multi-query function you wrote is very unsafe. Running something like
userQuery("'; delete from user; select * from user where username='");
will actually delete all users from your user table. Assuming $username represents raw user input without proper escaping, the consequences can be catastrophic.
You could possibly improve the above and do the escaping on your own using mysqli::real_escape_string, but there are many more sophisticated ways to do hacks like one above. Prepared statements are all in all a better solution.
Related
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.
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.
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.
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/
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.