parameterized query without preparing statement in PHP - php

Is there an API in MySQLi, PDO or in PHP that use parameterized query but not preparing it for recall later? I found it in ADO.NET when we dont call .Prepare() method of SQLParameter, but I didn't find this in PHP.

Prepared statements are sent to the database server with the values separated from the query. If you wanted to get the user with ID 1337, using PDO you would do this;
$sql = 'SELECT u.id, u.username FROM users u WHERE u.id = :theUserIdToGet LIMIT 1';
$stmt = $db->prepare($sql);
$stmt->bindValue(':theUserIdToGet', 1337);
$result = $stmt->fetch();
In a traditional query this would just be;
$sql = 'SELECT u.id, u.username FROM users u WHERE u.id = ' . 1337 . ' LIMIT 1';
$stmt = $db->query($sql);
$result = $stmt->fetch();
The first example clearly requires more code, however it has the following benifits;
Security - The values (just one in this case; 1337) are sent to the database server separately. The database server safely checks these values for bad characters and inserts them into the query before execution. Note that some query API's will emulate this, but it still offers a great deal of safety.
Readability - When adding more than a couple of parameters to a query, it gets very messy if concatenating strings ("WHERE id = " . $var1 . " AND " . $var2 . " = 1", etc).
Performance (occasionally) - It is true that prepared statements are vastly quicker when executed many times, but in practice this is very infrequent. The performance overhead of preparing a query over query() is negligible.
Prepared statements should always be used when inserting variables into a query because of their legibility and security.
PDO is generally considered to be very good, I personally use it all the time. It's learning curve is gentle and many tutorials are available on the internet. It's documentation is here

Related

MySQL Injection Confusion, How Does it Actually Protect?

I've been reading about MySQL Injection as I've just started adding prepared statements to my site. I wanted to know a bit more about how it actually protects and after reading some, I don't think I've done it correctly.
I was reading from here: http://www.tizag.com/mysqlTutorial/mysql-php-sql-injection.php
I really don't understand how it can be 'injected' or how prepared statements get around it. Particularly this bit:
Normal: SELECT * FROM customers WHERE username = 'timmy'
Injection: SELECT * FROM customers WHERE username = '' OR 1''
When using SELECT, the things I use for WHERE are only ID or username. They can't change their ID and the username is validated when they sign up by this:
function protect($string) {
global $con;
return mysqli_real_escape_string($con,strip_tags(addslashes($string)));
}
So is this "protect()" preventing MySQL injection?
If so, what are the uses for prepared statements? Is this protection correct?
Instead of
$car = 'nissan';
$update_car = mysqli_query($con,"UPDATE stats SET stats.car = $car WHERE stats.id = 4");
I put:
$car = 'nissan';
$query = "UPDATE stats SET stats.car = $car WHERE stats.id = 4";
$update_car = mysqli_query($con,$query);
If that is correct, I don't understand how that does anything besides just adding another line of code?
EDIT
First prepared statement, any good?
$getusername = mysqli_prepare($con, "SELECT users WHERE users.username = '",mysqli_real_escape_string($username),"'");
Firstly, let's look at your attempt at escaping:
function protect($string) {
global $con;
return mysqli_real_escape_string($con,strip_tags(addslashes($string)));
}
There are 2 mistakes here: Firstly, addslashes is doing the same job as mysqli_real_escape_string (but doing it badly), so remove that.
Secondly, you should always sanitise for the context you're working in. So, when generating SQL, you sanitise for SQL; when generating HTML, sanitise for HTML. So putting strip_tags in here doesn't make sense, because it's to do with HTML, but this is apparently an SQL escaping function. Do that separately, when you're preparing output in your templates.
In short, just mysqli_real_escape_string on its own would be better than what you have here.
Next, let's look at parameterising the query:
$car = 'nissan';
$query = "UPDATE stats SET stats.car = '$car' WHERE stats.id = 4";
$update_car = mysqli_query($con,$query);
This statement isn't prepared or parameterised - as far as the database is concerned, it's still just a string of SQL. If $car is actually set from user input (e.g. $car = $_GET['car'];), then you can insert any piece of SQL in the middle of the query:
$car = "nissan'; DROP TABLE stats; --";
$query = "UPDATE stats SET stats.car = '$car' WHERE stats.id = 4";
$update_car = mysqli_query($con,$query);
// MySQL will now drop your table; oops!
// UPDATE stats SET stats.car = 'nissan'; DROP TABLE stats; --' WHERE stats.id = 4
Adding $car = mysqli_real_escape_string($car); will correctly escape the ' in the input, stopping it ending the string and starting a new SQL statement.
Parameterised queries avoid the problem a different way: they tell the database which parts of the query are supposed to be SQL, and which are just data provided by the user. It looks like this:
$car = "nissan'; DROP TABLE stats; --";
$query_with_placeholder = "UPDATE stats SET stats.car = ? WHERE stats.id = 4";
// Note the ?, without quotes, represents somewhere for data to be put by MySQL
$prepared_statement = mysqli_prepare($con, $query_with_placeholder);
// Now we tell MySQL what to put in the placeholder
mysqli_stmt_bind_param($prepared_statement, 's', $car);
// And execute it
mysqli_stmt_execute($prepared_statement);
Because $car is never actually inserted into the SQL, just passed as a separate parameter, there is no way of it injecting anything nasty, and we don't need to do any additional escaping.
Also note that mysqli_real_escape_string is to prevent injection with strings. If you have a (for example) integer field then escaping the passed variable to cope with a quote doesn't really help as injection doesn't require the quote to work.
For example:-
$some_field_expected_to_be_int = '1 OR 1=1';
$query = "SELECT * FROM users WHERE id = ".mysqli_real_escape_string($con, $some_field_expected_to_be_int);
would still give a piece of SQL reading:-
SELECT * FROM users WHERE id = 1 OR 1=1
and return everything.
In such a case you should make sure it is an integer:-
$some_field_expected_to_be_int = '1 OR 1=1';
$query = "SELECT * FROM users WHERE id = ".(int)$some_field_expected_to_be_int;
Personally both prepared statements and escaping fields have their places. Prepared statements make it harder to forget to escape items and with many databases they give a performance advantage, but the mysqli placeholders are not readable, getting a statement out for debugging is not workable and it becomes a nightmare when used for heavily dynamic sql. But escaping leaves you with the risk you will forget somewhere and the code can look messy.
EDIT - to add a bit on prepared statements.
We use a couple of in house database classes which separate things a bit from mysql / mysqli / pdo / sql server, but for a basic example of using prepare and a bound parameter:-
<?php
if($stmt = $this->db->prepare("SELECT users WHERE users.username = ? "))
{
$stmt->bind_param('s', $username);
$stmt->execute();
}
?>
In this the SQL is not built up using the variable (which could have been manipulated), rather the variable is passed as a parameter.
Escaping the data and using prepared queries both protect against SQL injection. But escaping is more error-prone, because it's easy to forget to call it in all the places you need it. If you use prepared statements, the protection happens automatically.
There's no significant difference between
$update_car = mysqli_query($con,"UPDATE stats SET stats.car = $car WHERE stats.id = 4");
and
$query = "UPDATE stats SET stats.car = $car WHERE stats.id = 4";
$update_car = mysqli_query($con,$query);
This is just a stylistic choice. The second version can be useful when you want to insert debugging statements, e.g.
$query = "UPDATE stats SET stats.car = $car WHERE stats.id = 4";
echo $query;
$update_car = mysqli_query($con,$query);
Popular practice is to both sanitize input and use prepared statements with your queries whenever you have a possible user input variable.
Sanitation should also prevent users from overflowing your variables and upload large quantities of data to your application.
Preparing statements is your second measurement of security, it prevents mistakes you might make later, like forgetting to escape input or not realising what is actually user input next time you refactor your application.
Any time you don't properly guard against injection, you open your project up to users deleting data, modifying data or uploading malicious code to your application. (Do you really want someone to upload javascript in a textfield?)

An alternative to SQL concatenation for search options?

I'm a novice programmer, and I've inherited an application designed and built by a person who has now left the company. It's done in PHP and SQL Server 2008R2. In this application, there's a page with a table displaying a list of items, populated from the database, with some options for filters in a sidebar - search by ID, keyword, date etc. This table is populated by a mammoth query, and the filters are applied by concatenating them into said query. For example, if someone wanted item #131:
$filterString = "Item.itemID = 131";
$filter = " AND " . $filterString;
SELECT ...
FROM ...
WHERE...
$filter
The filter is included on the end of the URL of the search page. This isn't great, and I'm fairly sure there are some SQL injection vulnerabilities as a result, but it is extremely flexible - the filter string is created before it's concatentated, and can have lots of different conditions: E.g.$filterString could be "condition AND condition AND coindtion OR condition".
I've been looking into Stored Procedures, as a better way to counter the issue of SQL Injection, but I haven't had any luck working out how to replicate this same level of flexibility. I don't know ahead of time which of the filters (if any) will be selected.
Is there something I'm missing?
Use either Mysqli or PDO which support prepared/parameterized queries to battle sql injection. In PDO this could look something like this
$conditions = '';
$params = array();
if(isset($form->age)) {
$conditions .= ' AND user.age > ?'
$params[] = $form->age;
}
if(isset($form->brand)) {
$conditions .= ' AND car.brand = ?'
$params[] = $form->brand;
}
$sql = "
SELECT ...
FROM ...
LEFT ...
WHERE $conditions
";
$sth = $dbh->prepare($sql);
$sth->execute($params);
$result = $sth->fetchAll();
From the manual:
Calling PDO::prepare() and PDOStatement::execute() for statements that will be issued multiple times with different parameter values optimizes the performance of your application by allowing the driver to negotiate client and/or server side caching of the query plan and meta information, and helps to prevent SQL injection attacks by eliminating the need to manually quote the parameters.
http://no1.php.net/manual/en/pdo.prepare.php

query multiple columns php/mysql

new to php and am enrolled on a course, so can ask tutor tomorrow if this is more complicated than i think it might be!
I have an sql query, and it works fine. But I am trying to add and 'and' in the select statement.
This is what I have at the minute
$query = "SELECT * from table1 where table1.age <= " . $_POST['min_age'] ;
I have a 'region' input on my linked html page and want results to be returned only if the min_age and region values match those inputted by the user.
I have tried adding an 'and where' but it doesn't work and I am not sure if it is because of the multiple "'s or if what I am trying to do needs a different method?
Thanks
If you need multiple conditions, just separate them with AND:
... WHERE table1.age <= ? AND table1.region = ?
No need to use WHERE again. Just like you wouldn't need to use if() more than once if you were writing a complex condition in PHP.
PS: This isn't directly related to your question, but you should get into the habit of not putting $_POST or $_GET variables directly into your SQL queries. It's a good way to get hacked! Ask your tutor about "SQL injection," or read my presentation SQL Injection Myths and Fallacies.
I know you're just starting out, but if you were training to be an electrician, you would place a high priority on learning how to avoid being electrocuted or how to avoid causing a fire.
Here's how I would write your query using mysqli. One advantage of using query parameters is you never need to worry about where you start and end your quotes.
$query = "SELECT * from table1 where table1.age <= ? AND table1.region = ?";
$stmt = $mysqli->prepare($query) or trigger_error($mysqli->error, E_USER_ERROR);
$stmt->bind_param("is", $_POST["min_age"], $_POST["region"]);
$stmt->execute() or trigger_error($stmt->error, E_USER_ERROR);
The other good habit I'm showing here is to always report if prepare() or execute() return an error.
If you must interpolate variables into your SQL, first make sure you protect the variables either by coercing the value to an integer, or else by using a proper escaping function like mysqli_real_escape_string(). Don't put $_POST variables directly into the string. Also you don't have to stop and restart the quotes if you use PHP's syntax for embedding variables directly in double-quoted strings:
$age = (int) $_POST["min_age"];
$region = $mysqli->real_escape_string($_POST["region"]);
$query = "SELECT * from table1 where table1.age <= {$age}
AND table1.region = '{$region}'";

Secure against SQL Injection - PDO, mysqli [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Best way to prevent SQL Injection in PHP
I just found that my website is vunerable.
Since it's connected to a DB and have functions like: Register, Change Password, Notices, etc... and SUPOSING it's fully vulnerable.
What should I look for into the code in order to start making it safe?
I mean, I did some researches and everywhere, everyone says different things about security.
"Use PDO."
"Use mysql_real_escape_string."
"Use addslashes."
What exactly should I look for??
"$_POST" and "$_GET" variables??
"$_SESSION" variables?
SQL querys?
$sql = "select * from user";
$sql = "update user set user="new_user_name";
$sql = "insert into user (user) values ('userid')";
What should I do in each case?
Please, help me to know what and where I must go.
Thank you.
Following are the points to be considered for making safe php application.
USE PDO or mysqli
Never trust any inputs. Consider every variable viz $_POST, $_GET, $_COOKIE, $_SESSION, $_SERVER as if they were tainted. Use appropriate filtering measure for these variables.
To avoid XSS attack use php’s builtin functions htmlentities,
strip_tags, etc while inserting the user input data into the
database.
Disable Register Globals in PHP.INI
Disable “allow_url_fopen” in PHP.INI
Don’t allow user to input more data than required. Validate input to
allow max number of characters. Also validate each field for
relevant datatypes.
Disable error reporting after Development period. It might give
information about database that’ll be useful to hackers.
Use one time token while posting a form. If token exist and matches
the form post is valid otherwise invalid.
Use parametrized database queries
Use stored procedures
You can google for each point for more details.
HOpe this helps
What you should look for: Any data send from the client/user. Sanitize/escape this data.
PDO can sanitize queries (using PDO::prepare) and supports multiple SQL systems.
For MySQL, use MySQLi. mysqli_real_escape_string is the function to use for sanitizing data if you are using MySQL.
None of the SQL queries you provided are actually vulnerable to SQL injection.
SQL injection vulnerabilities happen because SQL input is not properly escaped.
For example:
$sql = "select * from users where user_id =" . $_GET['user_id'];
Consider if I passed in the following:
http://some_server.com/some_page.php?user_id=123%20or%201=1
The query when executed would end up being:
select * from users where user_id = 123 or 1=1
To fix this, use parameterized queries:
$query = "select * from users where user_id = ?"
When you bind the user_id value to the query, the data access layer will escape the input string properly and the following would be executed:
select * from users where user_id = '123 or 1=1' which would not return any rows, preventing the injection
If using PHP and the mysql extension:
$sql = "select * from users where user_id = '" . mysql_real_escape_string($_GET['user_id']) . "'";
Keep in mind you need to escape ALL input that is going into a SQL query:
$sql = "select id_column from some_table where id = 1";
$stmt = mysqli_query($conn, $sql);
if($stmt === false) die(mysqli_error($conn) . "\n");
while($row = mysqli_fetch_assoc($conn, $stmt) {
$sql = "update some_other_table set some_value = 'new value' where some_column = '" . mysqli_real_escape_string($conn, $row['id_column']) . "'";
....
}
This is because values you select from the database might include characters that are not safe for execution in a SQL statement, like the name "O'Hara" or example.
}
I've been using PDO.
An example for that in your case:
<?php
$stmt = $dbh->prepare("insert into user (user) values (?)");
$stmt->bindParam(1, $name);
$name = 'ValueHere';
$stmt->execute();
?>

Why does PDO manual say that SQL injection is still possible with PDO?

http://php.net/manual/en/pdo.prepared-statements.php
If an application exclusively uses prepared statements, the developer can be sure that no SQL injection will occur (however, if other portions of the query are being built up with unescaped input, SQL injection is still possible).
What are the possible scenarios where some of the input is unescaped? Is that even possible if all the other input goes into the database using PDO?
I'm thinking of the scenario where other input is processed with mysql_* functions and not escaped with mysql_real_escape_string. Is there anything else that could be a threat?
Thanks a lot. Regards
It means you cannot use untrusted values directly e.g. as a column or table name - or as a LIMIT parameter.
For example, this is safe:
$query = "SELECT * FROM tbl WHERE col = ?";
while these aren't:
$query = 'SELECT * FROM tbl WHERE col = ? LIMIT ' . $_GET['limit'];
$query = 'SELECT * FROM tbl WHERE ' . $_GET['field'] . ' = ?';
$query = "SELECT * FROM tbl WHERE col = ? AND othercol = '" . $_GET['other'] . "'";
$query = 'SELECT * FROM ' . $_GET['table'] . ' WHERE col = ?';
Basically, prepared statements' placeholders are meant to be used in places where you would have used an escaped value within single quotes in a classical query.
In case you wonder why databases usually do not support placeholders for things like table names: Besides the fact that dynamic table/column names are not that common, the database engine usually optimizes a prepared statement when it's prepared. This however cannot be done properly without knowing exactly which tables/columns are accessed.
Consider this:
$sql = "SELECT * FROM ".$_GET['tablename']." WHERE somecol = ?";
Because I populated the table name with un-escaped user input, it would be possible to pass in for example public_table p LEFT JOIN hidden_table h ON h.id = p.id and get results you didn't want me to, even though you have escaped the value passed to the somecol comparison.
The point is that while prepared statements safely escape any user input you pass to a ? in the query, they can't escape data that already existed in the string before you passed it to prepare().
It means don't be lured into thinking PDO is magic pill...if you don't use prepared statements, you will still be vulnerable.

Categories