How come this vulnerable PDO works instead of prepared statement? [duplicate] - php

This question already has answers here:
Can PHP PDO Statements accept the table or column name as parameter?
(8 answers)
Closed 7 years ago.
There is only one way my PDO query returns result I want, but proper prepared statement gives out only column name.
This returns column name instead of queried row:
$queryPrice = "SELECT :zone FROM express WHERE kg >= :kg LIMIT 1";
$stmt = $conn->prepare($queryPrice);
$stmt->bindParam(':zone', $zone, PDO::PARAM_STR);
$stmt->bindParam(':kg', $_SESSION['weight'], PDO::PARAM_STR);
$stmt->execute();
$price = $stmt->fetchColumn();
This works, but is vulnerable to injection:
$queryPrice = "SELECT $zone FROM express WHERE kg >= :kg LIMIT 1";
$stmt = $conn->prepare($queryPrice);
$stmt->bindParam(':kg', $_SESSION['weight'], PDO::PARAM_STR);
$stmt->execute();
$price = $stmt->fetchColumn();
Why doesn't prepared statement for column name work?
Is there a safe way to achieve desired results?

On the second thought your question appears to be caused by bad database design.
Instead of having zones as columns in the table, you have to have them as data in the single column in another table. And it is clearly proven by the fact that you are trying to address a column name the way only data have to be addressed.
You have reorganize your table, leaving only one column for zones, name for example. And you'll be able to select your zone with a query like this
SELECT name FROM zones WHERE kg > :kg

Related

prepared statement without values and before html output [duplicate]

This question already has answers here:
Can you omit PDO prepare if there's no placeholder/dynamic data in a query?
(3 answers)
Closed 4 years ago.
$sql = "select col1, col2, col3 from t1 order by date desc limit 500"
There is no place for binding anything, so do I need (and how) to make a prepared statement?
Another example:
$sql = "select col1 from t1 where col1 = 'val1' order by date desc"
If this code is placed before html output (while loading the page, without any user input values), do I need the prepared statement?
I suppose sql injection is not possible if there is no yet any interaction with users.
You don't need prepared statements if the query isn't expecting user supplied arguments.

Selecting one celd in the column result from SQL with PDO

I have this situation after my SQL stament: One single column with the same result. For example, the age of all people with blue eyes and green jeans, will return me one column "age" with the result for example 50 years (because all people with this characteristics have 50), repeted as many time as there are people with this parameters in the DB.
How I can do in PDO (or SQL) to filter or to get only one result, or only one fild (50)?
I try: fetchAll(PDO::FETCH_ASSOC) and fetchColumn() but both return a array or nothing
It's SQL.
SELECT age FROM people WHERE eyes='blue' AND jeans='green' LIMIT 1
Note that LIMIT part that will limit the results to only one row, which you'll be able to get with PDO's fetchColumn():
$sql = "SELECT age FROM people WHERE eyes='blue' AND jeans='green' LIMIT 1";
$age = $pdo->query($sql)->fetchColumn();

PDO with LEFT JOIN and ORDER BY [duplicate]

This question already has answers here:
How do I set ORDER BY params using prepared PDO statement?
(7 answers)
Closed 9 years ago.
I have this code
$query_search = $this->db->prepare("SELECT* FROM table1 LEFT JOIN table2 ON (table1.id=table2.id) WHERE table1.nome LIKE ? ORDER BY ? DESC");
if($query_search->execute(array($cliente_procura."%",'table2.'.$ordem)))
{
//code
}
But I'm having some problems with the ORDER BY clause.
How can I use PDO and make sure my tables are in the order I want?
Binding the column names is not possible with prepared statements.
You need to use the age-old method of binding them in strings like this:
$query_search = $this->db->prepare(" SELECT *
FROM table1
LEFT JOIN table2
ON (table1.id=table2.id)
WHERE table1.nome
LIKE ?
ORDER BY table2." . $ordem . " DESC");
if( $query_search->execute( array($cliente_procura."%") ) )
From the Stackoverflow PDO tag wiki - https://stackoverflow.com/tags/pdo/info
PDO Prepared statements and identifiers.
PDO has no placeholder for identifiers, so a developer must manually
format them. To properly format an identifier, follow these two rules:
*Enclose identifier in backticks.
*Escape backticks inside by doubling them.
see - Can PHP PDO Statements accept the table or column name as parameter?
or - Which tokens can be parameterized in PDO prepared statements?
see also this comment/example from the php manual - http://us3.php.net/manual/en/book.pdo.php#69304

PDO prepared statement with conditions not working

I am trying to to get my data from MYSQL using PDO but I am not having any luck.
Here is what I have tried:
$postQuery = $DBH->prepare("SELECT title, views, rating, thumb FROM posts WHERE category=:category and status=1 ORDER BY :sort DESC");
$postQuery ->bindParam(':category', $category);
$postQuery ->bindParam(':sort', $sort);
$postQuery ->execute();
This works without errors but it returns all of the posts in alphabetical order, ignoring the category and the sort.
I tried this:
$postQuery = $DBH->query("SELECT title, views, rating, thumb FROM posts WHERE category={$category} and status=1 ORDER BY {$sort} DESC");
This did work but I don't get the protection of the prepared statement. Any ideas on why one statement works but the other one does not?
Your bound parameter :sort gets expanded to a string literal, not a SQL identifier. That is, you are effectively evaluating something along the lines of:
ORDER BY 'rating' DESC
Since literals like this are constant for every record, it has no effect on the order of the resultset.
You can't parameterise identifiers, so must concatenate that part of the SQL into your prepared statement (the safest way is to set $sort from a predetermined set of safe values, based on whatever logic is appropriate to your needs).
You can't use place holders in ORDER BY clauses. See this question: How do I set ORDER BY params using prepared PDO statement?

SQL injection even when the variable is escaped [duplicate]

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 2 years ago.
The sql injection will work only when my query looks like below sample
SELECT * FROM login WHERE id = $my_id_va;
Assume if my query is
SELECT * FROM login WHERE id = $my_id_va ORDER BY id DESC
Than I will get following error
#1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'order by id desc' at line 1
So, this 1 or 1=1; SHOW TABLES will not work, correct?
My site was hacked successively many times.
I want one quick answer: When my query looks like the following one, what ways or which types of query can they use to hack my site?
SELECT * FROM login WHERE id = $my_id_va ORDER BY id DESC
What are the ways to execute the show table in the following query
SELECT * FROM login WHERE id = $my_id_va ORDER BY id DESC
I am also using escaping function to handle the query string values, like mysql_real_escape_string($my_id_va). Yes, obviously this for single related hack, but not sure.
Added some more
SELECT EventActuallyCharged, EventDate FROM tblevent WHERE EventDate between '2011-07-21 or 1=1; SHOW TABLES --' and '2011-07-31' ORDER BY EventDate DESC
but show table not worked
If you are using PHP5, use parametarized query, use PDO.
Int cast
If id is a number, you can int-cast your variable as well. Integers are safe to use:
$x = (int)$yourInputVar;
$s = "select * from Table where id = $x";
mysql_real_escape_string
If you want to pass a string, you can, and should, use mysql_real_escape_string, but this function escapes only those characters that are inside the string. You will still need to add quotes around the string, so:
$x = mysql_real_escape_string('hello');
$s = "select * from Table where id = $x";
.. will result in the query: select * from Table where id = hello. This is obiously not a valid query, since hello should be in quotes.
Change the query to:
$x = mysql_real_escape_string('hello');
$s = "select * from Table where id = '$x'";
.. and everything works fine. You add the quotes around, and mysql_real_escape_string takes care of special characters inside the string, if any.
Parameters
Another solution is to use parameterized queries. This can by done using MySQLi or PDO. The advantage is that you only tell your database where a variable should be inserted, and the database takes care of the escaping yourself.
It also may add a performance benefit, because these queries could be cached without their parameters, make a more efficient use of the query cache. This doesn't really work yet in current versions of MySQL, though.
You are right that 1 or 1=1; SHOW TABLES will give a syntax error but this will work:
1 or 1=1 --
The -- comments out the rest of the query.
In your case the value is an integer so instead of using mysql_real_escape_string you can use intval.
If you set $my_id_va to:
1 or 1=1; SHOW TABLES --
The -- will comment out the rest of the command, effectively terminating it.
I'm not sure what effect mysql_real_escape_string will have on the query. What you should be doing is parameterized queries.
1. First query somehow secured
$sql = sprintf('SELECT * FROM login WHERE id = %d ORDER BY id DESC', mysql_real_escape_string($my_id_va));
2. Second query somehow secured
$sql = sprintf("SELECT EventActuallyCharged, EventDate FROM tblevent WHERE EventDate BETWEEN '%s' AND '%s' ORDER BY EventDate DESC",
mysql_real_escape_string($start_date),
mysql_real_escape_string($end_date));
Read the docs about sprintf if you don't understand it.
However, as others have said, it would be very very secure if you would use parameterized queries with a class such as PDO or MySQLi.

Categories