I'm using codeigniter and most of the time use active record for my queries (which automatically escapes them), but this query doesn't seem to fit neatly into it because of the variable. So I need to figure out how to escape the query manually.
Codeigniter docs suggest escaping the queries this way:
$sql = "INSERT INTO table (title) VALUES(".$this->db->escape($title).")";
My original query
$sql = "SELECT * FROM (`user_language`) WHERE `user_id` = '{$id}'";
My escaped query
$sql = "SELECT * FROM (`user_language`) WHERE `user_id` = '{$id}' VALUES(".$this->db->escape($user_language).")";
But I'm having trouble getting the syntax right. Error messages are:
PHP error message: Undefined variable: user_language
SQL error: syntax wrong...near 'VALUES(NULL)' at line 1
$sql = "SELECT * FROM `user_language` WHERE `user_id` = " . $this->db->escape($id);
if you want to select the language of the user given by $id it should work that way.
dealing with numbers an alternative would be:
$sql = "SELECT * FROM `user_language` WHERE `user_id` = " . (int)$id;
codeigniter does also support prepared statements as "query bindings":
The secondary benefit of using binds is that the values are
automatically escaped, producing safer queries. You don't have to
remember to manually escape data; the engine does it automatically for
you.
I'm confused why you say you cannot use the Active Record class with CI, this is a simple SQL call (example below uses method chaining):
$this->db->select('*')->from('user_language')->where('user_id', $id);
$query = $this->db->get();
Your $id is then escaped properly, and you mitigate any injection.
Personally I use AR whenever possible, it allows me to write quick efficient code, and not worry about the bad things with SQL calls (custom queries).
Related
The following code is returning no results where I use the variable in the code of $dep if I manually put the value in of 1 it returns the expected result. I have tried it with no quotes single quotes and double quotes. I have looked though loads of examples and I cannot see what I am doing wrong
$dep = 1;
if (!$names) {
$sql = "SELECT topic_id, topic_pid, ispublic, isactive, topic, dept_id FROM '.TOPIC_TABLE
. ' WHERE dept_id='$dep' ORDER BY `sort`";
$res = db_query($sql);
I'm pretty sure your error is related to wrong quotes used.
In your code, you write
$sql = "SELECT topic_id, topic_pid, ispublic, isactive, topic, dept_id FROM '.TOPIC_TABLE
. ' WHERE dept_id='$dep' ORDER BY `sort`";
After FROM, you are using single-quotes('), but your whole query has been enclosed into double-quotes("), so that creates the issue.
It should be:
$sql = "SELECT topic_id, topic_pid, ispublic, isactive, topic, dept_id FROM ".TOPIC_TABLE
. " WHERE dept_id='$dep' ORDER BY `sort`";
EDIT: Forgot to point out you should seriously use PDO or any other SQL Injection prevention methods. If, under any circumstance, your $dep variable could be sent via a public form, you could end up by having your DB dumped in the best case.
There's a syntax error in the second line of the query - if you want single-quotes in the query, then you need to enclose it all in double-quotes:
$sql = "SELECT topic_id, topic_pid, ispublic, isactive, topic, dept_id FROM ' .TOPIC_TABLE
. " WHERE dept_id='$dep' ORDER BY `sort`";
By the way, building a query like this, using string concatenation, is a REALLY BAD IDEA and leaves you open to SQL injection attacks - you should use prepared statements and parameters instead.
First as Fred -ii says make sure the if statement is executing properly. Then if dept_id is an integer value then you should not need the single quotes as scaisEdge says. Otherrwise the SQL looks fine. Make sure that there are in deed records in the database for the dept_id that is being passed in.
I am having this piece of code:
$result = mysqli_query($con , 'SELECT * FROM messages WHERE group = "'.$_POST['group'].'" ORDER BY date '.$_POST['order'].'');
I don't understand why it is always returning me false. The variables $_POST['group'] and $_POST['order'] aren't empty .
$_POST['group']='PHP'
$_POST['order']='DESC'
The conecction to the database is corect too.
GROUP is a mysql reserved word and needs to be quoted using backticks;
SELECT * FROM messages WHERE `group` = ...
You're also wide open to SQL injection, you should never add un-validated/un-escaped POST data in string format to your SQL. The safest way to do queries with user data is using prepared statements, or - as a less secure alternative - escape the data using mysqli_real_escape_string.
$result = mysqli_query($con , "SELECT * FROM messages WHERE group = '".mysqli_real_escape_string($_POST['group'])."' ORDER BY date '".mysqli_real_escape_string($_POST['order'])."'";
Try formatting the query like this and see if it helps your result. I also added mysqli_real_escape_string() to escape your input, as your query was wide open to SQL injection.
http://php.net/manual/en/mysqli.real-escape-string.php
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can PHP PDO Statements accept the table name as parameter?
Im writing a script that allows users to register and login to my site. Im using PDO prepare and execute to prevent SQL injections.
Building the query manually like this DOES work:
$a_query = "SELECT COUNT(*) FROM ". $login_table . "
WHERE `username` = ". $my_username . "
AND `password = " . $my_hash ;
$result_1 = $db->prepare($a_query);
$result_1->execute();
But when I try to use prepare correctly like this, it does NOT:
$a_query = "SELECT COUNT(*) FROM :table
WHERE `username` = :name
AND `password = :pass ;"
$result_1 = $db->prepare($a_query);
$result_1->bindParam(":table", $login_table);
$result_1->bindParam(":name", $my_username);
$result_1->bindParam(":pass", $my_hash);
$result_1->execute();
The error message I get from $result_1->errorInfo[2] reads:
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 ''customerlogin' WHERE `username` = 'guest' AND `password`
= 'qwerty' at line 1
As you can see, prepare() mysteriously slices off the first part of the query before sending it to mysql.
Can anyone explain to me why and how I can fix this?
As you can see, prepare() mysteriously slices off the first part of the query before sending it to
mysql.
It does not. It's just the error message handler which actually does that, trying to display only the relevant part of the query. Usually such an error message means "look at the query right before this part". So - it points out at the :table in your query.
Your query does not work because prepared statements do not support identifiers.
PDO, as any other raw API, is insufficient for any real-life query.
A developer should use database abstraction library methods in their application code, not raw API methods.
It will make life much easier and code shorter. For example, your whole code can be made into only 2 lines:
$sql = "SELECT COUNT(*) FROM ?n WHERE `username` = ?s AND `password = ?s";
$data = $db->getOne($sql, $login_table, $my_username, $my_hash);
And it would be safer than your whole screen-long code using raw PDO.
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();
?>
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.