MySQL Rejecting Query Syntax Based on Apostrophe Character - php

I am using MeekroDB (http://www.meekro.com/quickstart.php) to construct simple MySQL queries in PHP. Even simple queries are being rejected due to incorrect syntax. I noticed by writing queries manually in phpMyAdmin that queries are rejected if they use this syntax:
SELECT * FROM 'table name'
But accepted if they use this syntax:
SELECT * FROM `table name`
The only difference is a slightly different apostrophe. MeekroDB seems to be producing the first syntax by default, which is causing the queries to be rejected. Has anyone faced this before? Any solutions? I'm using WAMP Server and MySQL 5.5.24.
Note: Queries generated by MeekroDB are working if they do not contain an apostrophe or if the second apostrophe type is inserted manually. So:
$result = DB::query("SELECT DISTINCT `column` FROM `table`")
works but:
$result = DB::query("SELECT DISTINCT %s FROM %s", "column","table")
doesn't.

I hadn't heard about MeekroDB but it appears to be a simple database abstraction layer. Your second example:
$result = DB::query("SELECT DISTINCT %s FROM %s", "column","table")
... is invalid because neither "column" nor "table" are literal strings you want to inject. They're column/table names that are part of the SQL statement, not user-provided parameters.
This is a basic concept in most programming languages. SELECT foo is different from SELECT 'foo' in SQL for the same reason that echo md5(1); is different from echo 'md5(1)'; in PHP.
Update:
I suspect I wasn't clear enough. Using prepared statements to bind language constructs or object names is a misuse of any database library, MeekroDB or not. You are supposed to bind parameters that represent values, esp. those entered by end users, so you the value does not leak into SQL and breaks the query or change its meaning. But there're normally no tools to inject SQL commands or table names—they'd be of little use: if you allow the user to build arbitrary SQL queries, he's already been granted the power to do almost anything he wants.

Well since PHP doesn't treat strings the same way other languages do this is a somewhat bad idea. In essence they have tried to make it easier for developers but doesn't always happen. In reality what you could do is
$result = DB::query(sprintf("SELECT DISTINCT %s FROM %s", "column","table"));

Related

Escape a pdo query, is that necessary?

My question of to day is. Do i need to escape PDO in my script?
$columns = implode(", ",$column);
$query = ''.$query.' '.$columns.' FROM '.$table.'';
$dbh_query = $dbh->prepare($query);
$dbh_query->execute();
$dbh_querys = $dbh_query->fetchAll();
return $dbh_querys;
The whole script can be found at.
https://github.com/joshuahiwat/crud/blob/master/control/query_connector.class.php
Can someone explain why do i need a escape at this time or why not.
I like to hear from you, thanks a lot!
The parts of your query that are dynamic are the table name and column names. You can't use bind functions for these parts of the query. Bind functions can be used only for the parts of the query that would otherwise be a simple value in an SQL query. Like a numeric constant, or a quoted string or quoted date literal.
To avoid SQL injection from dynamic table names or column names, you have the following choices:
Use values that are predefined in your class, or otherwise certain to be safe. Don't use external content from users or any other source.
Use escaping. Note that the function PDO::quote() doesn't do the kind of escaping you need for table names or column names.
Create a "allowlist" of known table names and the column names for the respective table, and compare the dynamic input to the allowlist. If it doesn't match the allowlist, raise an error.
First of all you need to understand that the word you are using - "escape" - is meaningless.
What you probably mean is "to make your query safe from SQL injection". But, unfortunately, there is no such magic "escaping" that will make some abstract query safe.
The traditional query building assumes that all the query parts beside data values are hard-coded, while data values are bound via placeholders, like this:
$query = 'SELECT col1, col2 FROM some_table WHERE id = ?';
$stmt = $dbh->prepare($query);
$stmt->execute([$id]);
$row = $stmt->fetch();
This kind of a query considered safe.
In your case of a dynamically constructed query, every part is potentially vulnerable.
And here it is very important to understand that a burden of sanitizing all the query parts is entirely on this function. You cannot dismiss the danger simply claiming that your data is coming from the trusted source. That's a slippery ground because people often have no idea whether their source is trusted or not.
So, if take your question as "Do I have to protect this code from SQL injection", than the answer is - YES, YOU HAVE.
In the meantime you are protecting only a small part of your query - the data values. So you still have to protect (this term is much better than "escape") all other parts.
On a side note, your code is connecting to database every time it runs a query, which is highly inefficient and makes it impossible to use some database features.

Joomla db->query. What is the difference between quote types when filling query object

Im working under Joomla 3.x
There are many different solution for building query objects.
More recent documentations seems to prefer this method:
$query->select("*")
$query->from($db->nameQuote('#__example_table'))
$query->where($db->nameQuote('id')." = ".$db->quote('999999'));
In similar pages there are some exapmles named as "fully quoted":
$query = "
SELECT *
FROM ".$db->nameQuote('#__example_table')."
WHERE ".$db->nameQuote('id')." = ".$db->quote('999999').";
";
And straight forward method:
$query = " SELECT *
FROM #__example_table
WHERE 'id' = '999999';
";
What is the difference between this methods?
When, one of them does not work but other methods can be executed successfully?
All of those methods will work as long as you stick to those aspects of SQL that do not differ from driver to driver or do not care about multi-support.
However please note that your three examples are not equivalent in that you are treating 999999 as a string in the first two and as an integer in the last one.
In general if you care at all about multi-database support or if you want to be sure that your queries won't blow up because you accidentally use a reserved word as a field name and didn't quote it correctly, then the first example is the best (possibly modified based on whether you mean 9999999 or '999999').
Here's why
All names are quotes with the correct type of marks.
Things will be correctly escaped (unless you say not to).
All strings are quoted correctly
It will work on all of the supported databases.
It is easy to correctly add additional statements when you need to modify that query because JDatabaseQuery puts them together correctly whatever order you put the statements in.
In terms of what the difference between quote types, in SQL drivers there is usually a difference between backticks and single quotes, $db->quote() gives you single quotes and $db->quoteName() gives you backticks.

Hack prepare statement (read first)

I have this code:
<?php
$table = $_GET ["table"];
$query = "SELECT 1 FROM $table";
$st = $pdo->prepare($query);
$st->execute();
This is not the real code, but it is an example to get the idea.
If I make:
hacked.php?table=users;DROP TABLE users;
It will work, cause it is not correctly escaped.
However, if I want to update information like this:
hacked.php?table=users; UPDATE users SET name="abc" WHERE name="def";
It will not work, cause since it is escaped, pdo will convert the query to
SELECT 1 FROM users; UPDATE users SET name=\"abc\" WHERE name=\"def\";
and obviously it fails.
Is there anyway to make this query works?
EDIT 1
We have one guy in our team only devoted to check my code and hacked it. So I want to be ready if this can be in some way accomplished.
EDIT 2
I was already read this: Are PDO prepared statements sufficient to prevent SQL injection? but it really did not answered my question. However it gave me a way to go through. And the solution of #duskwuff was the same I came to. So, for the admins, if this should be removed or marked as a duplicate is ok. But I insist that this can be helpful for someone to know how pdo prepared can be hacked.
It will not work, cause since it is escaped, pdo will convert the query to
SELECT 1 FROM users; UPDATE users SET name=\"abc\" WHERE name=\"def\";
This is incorrect! PDO does not perform escaping on text that is interpolated into queries, as it has no awareness of what text was interpolated. What you're seeing is the result of PHP's deprecated magic_quotes feature adding backslashes to the content of request variables (like $_GET and $_POST). Even if this is enabled, it can be trivially avoided in a query like this one by using non-quoted constructs such as:
SELECT 1 FROM users; UPDATE users SET name = CHAR(97,98,99) WHERE name = CHAR(100,101,102)
(CHAR() is a MySQL function which constructs a string from a list of character code values. If you're using some other database, an equivalent function probably exists.)
Interpolating unescaped content directly into a query is never safe. Don't do it.
I think you are asking the wrong question. If you have code that is even remotely similar to this, then you have a huge problem with the way you're writing code... and probably with the way you're conceptualizing the problem that you need to solve, or you're working from a very bad design.
If, for some reason, you have a need for anything about the design of your database to be passed in on a URL query string or an http post, and if, for some reason, you think executing an unescaped query is the approach you need... then whatever you're doing, you're doing it wrong.
If, by some remote chance, you actually have a need to pass the name of a table to a web page, then the very least you must do is compare the input value to some kind of static structure to see if the input value is in the list... and then use the value from the list, or from something static, never from the input.
Simplistically something as primitive as the following would be a far superior approach, though arguably it is a bad design if table names, column names, or any database internals ever need to go out into browser-land.
$table = $_GET ["table"];
IF ($table == "users")
{
$query = "SELECT 1 FROM users;"
}
ELSEIF ($table == "points")
{
$query = "SELECT 1 FROM points;"
}
...

Trouble with LIKE MySQL query

I have the following MySQL query that I execute from a .php page
SELECT * FROM servers WHERE name LIKE '%$value%'
which, when executed, selects 0 rows (However, the query runs successfully, so I can't use mysql_error() to debug). When I run the query in PHPMyAdmin it selects the appropriate rows. Other queries such as
SELECT * FROM servers
work fine. I can put my code up here if it will help.
Edit: Here's something offering an improvement based on Marek's answer below. Please see the comments regarding the practice of putting variables directly into queries and consider using prepared statements. Anyway, here it goes.
PHP substitutes variables inside doubly-quoted strings, but not inside singly-quoted strings.
One quote character is just treated as an ordinary character within a string delimited by the other.
Putting that together, you can write:
$q = "SELECT * FROM servers WHERE name LIKE '%$value%'"; //Fine
You cannot write:
$p = 'SELECT * FROM servers WHERE name LIKE "%$value%"'; //Broken!
$q works because it's a doubly-quoted string, and the apostrophes are just ordinary characters. $p does not work because it's a singly-quoted string.
As pointed out by GoodFather below, you can also say ${value} to avoid ambiguities with the ambient string, e.g. $r = "ABC${value}DEF";.
You really need to look at doing this query more safely. This will help with your issue as well. As it stands, you are vulnerable to SQL injection. Look at the examples from the PHP manual for how to do it right:
http://php.net/manual/en/function.mysql-query.php
EDIT: From your comments you mentioned that you are already taking care of the string properly, which is great. The code below should fix your problem.
For example, you could rewrite your query statement (in PHP) like so:
$query = sprintf("SELECT * FROM servers WHERE name LIKE '%". mysql_real_escape_string($value) . "%'");
That will clean up your code and it will also handle the issue with your LIKE statement not working properly.
Here is another good article on the subject:
http://joshhighland.com/blog/2008/07/06/php-sprintf-sql-like/
Are you expecting a case-sensitive or case-insensitive query? I'm betting case-insensitive since you're expecting results but not seeing them. Take a look at your database's default collation or the table's specific collation and make sure it ends in _ci, whatever it is.

Are PHP MySQLi prepared queries with bound parameters secure?

Historically, I've always used
mysql_real_escape_string()
for all input derived from users that ends up touching the database.
Now that I've completely converted over to MySQLi and I'm using prepared queries with bound parameters, have I effectively eliminated the possibility of SQL injection attacks?
Am I correct in saying I no longer need
mysql_real_escape_string()?
This is my understanding and the basis of a project of mine:
http://sourceforge.net/projects/mysqldoneright/files/Base/MysqlDoneRight-0.23.tar.gz/download
This is not something I want to get wrong though as now that I've released it, it could affect others as well.
All user provided input will now end up in bind_parms.
The queries provided in the prepare phase are static.
Yes. Using the prepared query will escape parameters.
It's not so simple. You can use bound parameters instead of interpolating application variables into SQL expressions in place of literal values only:
$sql = "SELECT * FROM MyTable WHERE id = ".$_GET["id"]; // not safe
$sql = "SELECT * FROM MyTable WHERE id = ?"; // safe
But what if you need to make part of the query dynamic besides a literal value?
$sql = "SELECT * FROM MyTable ORDER BY ".$_GET["sortcolumn"]; // not safe
$sql = "SELECT * FROM MyTable ORDER BY ?"; // doesn't work!
The parameter will always be interpreted as a value, not a column identifier. You can run a query with ORDER BY 'score', which is different from ORDER BY score, and using a parameter will be interpreted as the former -- a constant string 'score', not the value in the column named score.
So there are lots of cases where you have to use dynamic SQL and interpolate application variables into the query to get the results you want. In those cases, query parameters can't help you. You still have to be vigilant and code defensively to prevent SQL injection flaws.
No framework or data-access library can do this work for you. You can always construct a SQL query string that contains a SQL injection flaw, and you do this before the data-access library sees the SQL query. So how is it supposed to know what's intentional and what's a flaw?
Here are the methods to achieve secure SQL queries:
Filter input. Trace any variable data that gets inserted into your SQL queries. Use input filters to strip out illegal characters. For instance, if you expect an integer, make sure the input is constrained to be an integer.
Escape output. Output in this context can be the SQL query which you send to the database server. You know you can use SQL query parameters for values, but what about a column name? You need an escaping/quoting function for identifiers, just like the old mysql_real_escape_string() is for string values.
Code reviews. Get someone to be a second pair of eyes and go over your SQL code, to help you spot places where you neglected to use the above two techniques.
When you bind parameters to a prepared statement, it escapes the data automatically, so you shouldn't escape it before you send it through. Double escaping is usually a bad thing. At the very least, it produces ugly results with extra escaped characters later on.

Categories