I know nothing about SQL injection apart from the process to block it.
I was wondering, if an attacker would modify my prepared statement from:
$DB = $Con->prepare("SELECT * FROM Test WHERE username=?");
$DB->bind_param('s',$Username);
$DB->execute();
And his statement he entered was:
x' DROP TABLE Test
How would the bind/prepared statement process this request?
Would it return an error or continue? as the bind_param links specific values to said SQL Statement?
No, the database would simply look for a record that has a username of x' DROP TABLE Test so you would probably end up with an empty result set.
When using bind_param, the values will be escaped for you. You should still validate the data to make sure it's correct, but it's safe from injection
Once you prepare a statement, it is pre-compiled. So any parameters you bind to it are sent as raw data and in no way could modify the SQL statement.
Your example would work fine, it would select all rows with the username x' DROP TABLE Test.
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 gone through various document (SO post as well) about how exactly Prepared statement of PDO protect user from SQL injection.
Although,I understand it protect user because in prepared statement,user record is directly not executing on server insted we are sending positional / named parameter ( ? / :name) and then we send actual data in execute statement, and because of that it saves us from SQL Injection.
Well, Now if I have below code for SQL :
$query = "select * from user where id = $user_input_id";
and user input id = 1
So query will be something like :
$query = "select * from user where id = 1";
This is perfect till now. But if user entre $id = "1; DROP TABLE users;" so query will be something like :
$query = "SELECT * FROM users where id=$id";
and hence ,it will execute
$query = "SELECT * FROM users where id=1; DROP TABLE users;";
It works and out user table will drop because this query directly execute:
Well,I have read that prepared statement can save user from this :
and prepared statement working like :
$data = "1; DROP TABLE users;"
$db->prepare("SELECT * FROM users where id=?");
$db->execute($data);
In execute statement as well,record with Drop table is passing,so how exactly it won't execute drop table statament ? execute also performing some part on server right ?
Anyone can please explain how exactly prepared statement here save user from SQL injection ?
Thanks
Without explicitly setting a type (see PDOStatement::bindValue() for an example), it will treat the passed value as a string, so it will do this effectively:
SELECT * FROM users where id='1; DROP TABLE users;'
Btw, this would actually happen if you're using emulated prepared statements (PDO::ATTR_EMULATE_PREPARES); without this, it will send the parametrised query first followed by the actual data.
That is why you can additionally set the type of binded data to the type you need.
$stm->bindParam(":id", $id, PDO:PARAM_INT)
Additionally, PDO does some escaping of the data, and the string you provided will not break the query at ;, but will be inserted as plain string in the db.
SQL injection is an attack against the SQL parsing step, not the statement execution step. In this, it has similarities to other parse attacks such as cross site scripting and XML injection attacks.
SQL injection works because the common (broken) technique of creating SQL statements by using string concatenation operators to combine both code and (untrusted) data in a single string allows for the possibility of a specially crafted string to violate the statement data protocol (typically by breaking out of a data context using string delimiters embedded in data), and allowing the attacker to manipulate the SQL parser into executing different code to that originally intended.
When one uses a prepared statement, one is telling the parser 'treat the statement purely as trusted code, and provide some slots into which I will insert the data for execution'.
When you drop the string '1; drop table users' into the data slot you created using the '?' placeholder, that string is not processed by the parser, and hence it has no opportunity to influence the parsing of the string : you made it impossible for the contents of the string to break out of a data context.
Using your example, the database will execute the equivalent statement to :
SELECT * FROM users where id="1; drop table users;"
This is a perfectly valid select statement, which may or may not return rows depending on the data in your tables, but which is almost certainly not going to work properly.
Nevertheless, the approach bypassed the attempt at SQL injection.
Be aware : using prepared statements is the ONLY generalised way to avoid SQL injection attacks. In general, attempts to filter untrusted input data are broken.
I have read somewhere here that using prepared statements in PDO makes your app only immune to first order SQL injections, but not totally immune to second order injections.
My question is: if we used prepared statements in all queries inlcuding SELECT queries and not only in INSERT query, then how can a second order sql injection be possible?
For example in the following queries there is no chance for a 2nd order injection:
write:
INSERT INTO posts (userID,text,date) VALUES(?,?,?)
read:
SELECT * FROM posts WEHRE userID=?
delete:
DELETE FROM posts WHERE userID=?
What you have read is a plain rubbish. Someone who wrote it just have no clue.
You should use prepared statements not for the query but for the data. Every time you have to add a variable into query, you have to make it via placeholder only. So, your query separation theory makes no sense: it doesn't matter if it SELECT or ALTER or GRANT or whatever. The only thing that matters - if any variable goes into query or not.
Since most people sermonize “the user is evil” and “don’t trust user input”, one may get the impression that once the data is in the database it’s ‘trusted’.
But SQL injections is not about trusted and untrusted data. SQL injection is the failure of ensuring that an SQL statement is interpreted as intended.
And this is where prepared statements/parameterization comes in play as it’s a technique to ensure that the parameters are interpreted as intended, i. e., as data and not as SQL code. And this should be applied to any data, regardless of its origin or whether it’s seen as ‘trusted’ or ‘untrusted’, simply to ensure the data is interpreted as intended.
I'm very new to PHP and programming in general. I've come across an article about security, although not an issue yet in my case, I'm sure it will come up in the future at some point.
The article in question was about database input.
I'm using PDO most of the time while dealing with databases, however I'm confused about some parts. Perhaps someone can shed some light on a few things.
As I understand it, prepared statements in PDO for example:
SELECT <column> FROM <table name> WHERE <something>
Doesn't get execute right away(well, obviously) but only when execute(); is called. And gets interpreted as is.
So having something like
"SELECT <column> FROM <table name> WHERE" . <userinput> OR 1=1;
Lets say userinput is the username
And
<userinput> OR 1=1
is a user input variable via a form or whatever, will get interpreted exactly like that, meaning the username will be
userinput OR 1=1
And obviously no username OR 1=1 will exist in the database so an error will be returned.
That this mean that PDO is safe(a strong word, I know) from things like SQL injection? Or other 'hacking' methods?
What can I use/do to sanitize user input in general?
Yes it is safe, you can look at it as sandbox, if you have SQL like SELECT FROM books, it guaranties that input from user will not get out of boundaries (like modifying sql query), so it is safe from 1st order injection, but not from 2nd.
What i mean? Well PDO PREPARED statements(because you can use pdo without preparing statements in php) guaranties that you sql query is safe, but it doesn't filters the actual value.
Consider example: suppose we get some value from the form, the value will be 1); DROP TABLE books and we will save it in our database using our prepared statement INSERT INTO books VALUES(<value1>, ...),so the query will be executed successfully, value 1); DROP TABLE books will be saved in our database, but evil code will no be executed, no drop value. But if you then use our stored value in standard query, not prepared one. You will get hurt. But if you everywhere use PDO prepared statement your are safe. But i advice to filter values anyway.
Make use of Prepared Statements on PDO and you can stop worrying about SQL Injection.
I am sorry as this is the simplest answer i could give for this question.
Source
EDIT :
Found this answer on SO
Statement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();
If "user" came from user input and the user input was
Robert'); DROP TABLE students; --
Then in the first instance, you'd be hosed. In the second, you'd be safe and Little Bobby Tables would be registered for your school.