how to check sql injection in codigniter? - php

I am working on codeigniter project. How can I know queries function in my models are preventing the sql injection.
Even I'm using different ways to insert data but how can i make sure that which one is safe .
Here's my code:
1) *****************
$data = array(
'name' => $_POST['name'],
'email' => $_POST['email'],
'phone' => $_POST['phone'],
'city' => $_POST['city'],
'current_salary' => $_POST['current_salary'],
'expected_salary' => $_POST['expected_salary'],
'reume_link' => $file_name,
'status' => 0,
);
$this->db->insert('my_table_name', $data);
2) **************************
$query = $this->db->query('SELECT distinct(name) as name FROM `my_table_name` WHERE city like "%'.$_POST['state'].'%" ');
$res = $query->result_array();
3) **************************
$query = $this->db->query("insert into my_table_name(nid,sid,cid,data) values('766','$sid',1,'".$_POST['adm_name']."')");
Are the codeigniter function prevent sql injection default or I strictly need to use prepare statement / bind parameter.
Are the simple CI function not safe to use ?

Here is an example of how to use prepared statements -
$sql = 'SELECT distinct(name) name FROM `my_table_name` WHERE city like ?';
$query = $this->db->query($sql, array("%$_POST[state]%"));
means you have to substitute actual data with ? marks and pass it in the form of array as a second parameter.
Most of ActiveRecord methods (like insert, get and such) are safe too, as long as you are following guidelines.

You should use $this->db->escape_str for every variable you put inside your query. Another option (even a better one) is to use prepared statements.

If you were using CodeIgniter's Active Record methods it'll automatically escape queries for you to prevent injection.
$this->db->select('*');
$this->db->from('table_name');
$this->db->where('column_name', $val1);
$this->db->get();
If you don't want to use CI Active Records then there's a function i.e $this->db->escape() in CI
$data1 = $this->db->escape($data1);
$this->db->query("SELECT * FROM table_name WHERE var = '$data1'");
Or you can use query bindings as
$sql = 'SELECT * FROM table_name WHERE var = ?';
$this->db->query($sql, array($var));
Even instead of using $_POST and $_GET CI have its method of $this->input->post() and $this->input->get() respectively

For protection always use $this->input->post('name_of_input') and $this->input->get('name_of_input') instead of $_POST[] & $_GET[]

check this link for documentation
in config.php set
$config['global_xss_filtering'] = True;
or use xss_clean in validation, check the link for documentation

Related

Is the in_array function a safe way of blocking code injection/sql injection?

If i have a php file which is receiving a $_GET['value'] is it safe from sql injection or code-injection for me to start my php file with
if (in_array($_GET['value'], $allowed_values);)
{ /* normal page code handling the $_GET['value'] */
} else { unset($_GET['name'])
}
$allowed values is obviously an array of all values which i am expecting as safe for $_Get['value']. Is this still unsafe? Thank you.
Yes, that's a common and safe technique that can be used in situations where query parameters can't be used. For instance, if the value will be used as a table or column name, you can't provide it as a query parameter, you have to substitute it directly into the SQL string. Whitelisting like this is the recommended way to ensure that this is safe.
It depends on the values in the $allowed_values array, and how you are interpolating the value into your SQL query.
For example:
$allowed_values = [ 'a word' ];
if (in_array($_GET['value'], $allowed_values)) {
$sql = "SELECT * FROM mytable WHERE id = {$_GET['value']};";
}
Definitely not safe. It results in the SQL:
SELECT * FROM mytable WHERE id = a word;
This is a syntax error.
Why would you not just use SQL query parameters? Then you don't need to worry if it's safe or not. Query parameters separate the values from the SQL parsing, so there's no way any kind of value can cause SQL injection.
You won't have to have an $allowed_values array. You won't have to remember to check if the GET input is in the array. You won't have to worry about quoting or escaping.
It's true that query parameters only work for values, that is in place of a quoted string literal or quoted datetime literal or numeric literal. If you need other parts of your query to be dynamic, like the table name or column name or SQL keywords, etc. then use an allow-list solution like you are showing.
But the more common case of interpolating dynamic values is better handled by query parameters:
$sql = "SELECT * FROM mytable WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt-execute( [ $_GET['value'] ] );
let's discuss this thing in little details:
Your code is like this :
if (in_array($_GET['value'], $allowed_values);) {
...........
$sql = "SELECT * FROM mytable WHERE id = $_GET['value']";
...........
}
else {
unset($_GET['name'])
}
now let's assume, you have some values :
the in_array() function will allow only some pre-defined values, you couldn't have the option to take custom user input by $_GET, but as only pre-defined values are allowed,any SQL command will be safe inside if statement.
now take this example of $allowed_values array :
$allowed_values = ['some details' , 'another details' ,3, ' 105; DROP TABLE mytable;', 22 , 'ok'];
If any of these array values have a string that can have potential SQL injection capability, then there will be an issue. but I think you will not put any such string in the array $allowed_values. ( in this above-mentioned example, index 3, ' 105; DROP TABLE mytable;' can delete the table mytable ). else the SQL command will be safe.
now you can add an extra layer of safety in the code, by using PDO for any SQL query. (in this example you do not need that, as in_array() function is 100% safe unless you yourself put any malicious code in the array, as per my above-mentioned example). but for other types of user input where you have to do some SQL query depend on the user input, you can use PDO -prepared statement.
a PDO example is this :
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDBPDO";
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("INSERT INTO photos (username, kname) VALUES (?, ?)");
$stmt->execute([ $username , $kname ]);
For more info, try w3school link: https://www.w3schools.com/php/php_mysql_prepared_statements.asp

Unable to locate error with PDO prepared statement [duplicate]

I'm working on a dynamic query that uses variables to specify a table, a field/column, and a value to search for. I've gotten the query to work as expected without the variables, both in phpMyAdmin (manually typing the query) and from within the code by concatenating the variables into a complete query.
However, when I use bindParam() or bindValue() to bind the variables, it returns an empty array.
Here's my code:
function search_db($db, $searchTerm, $searchBy, $searchTable){
try{
$stmt = $db->prepare('
SELECT
*
FROM
?
WHERE
? LIKE ?
');
$stmt->bindParam(1, $searchTable);
$stmt->bindParam(2, $searchBy);
$stmt->bindValue(3, '%'. $searchTerm.'%');
$stmt->execute();
} catch(Exception $e) {
return array();
}
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// database initialization, creates the $db variable
require(ROOT_PATH . "include/database.php");
$matches = search_db($db, 'search term', 'myColumn', 'myTable');
var_dump($matches);
Expected results: an array of rows from the database
Actual results: an empty array
Unfortunately, placeholder can represent a data literal only. So, a very common pitfall is a query like this:
$opt = "id";
$sql = "SELECT :option FROM t";
$stm = $pdo->prepare($sql);
$stm->execute([':option' => $opt]);
$data = $stm->fetchAll();
This statement will return just a literal string 'id' in the fieldset, not the value of the column named id.
So, a developer must take care of identifiers oneself - PDO offers no help for this matter.
To make a dynamical identifier safe, one has to follow 2 strict rules:
to format identifiers properly
to verify it against a hardcoded whitelist.
To format an identifier, one has to apply these 2 rules:
Enclose the identifier in backticks.
Escape backticks inside by doubling them.
After such formatting, it is safe to insert the $table variable into query. So, the code would be:
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
However, although such formatting would be enough for the cases like ORDER BY, for most other cases there is a possibility for a different sort of injection: letting a user choose a table or a field they can see, we may reveal some sensitive information, like a password or other personal data. So, it's always better to check dynamical identifiers against a list of allowed values. Here is a brief example:
$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed);
$field = $allowed[$key];
$query = "SELECT $field FROM t"; //value is safe
For keywords, the rules are same, but of course there is no formatting available - thus, only whitelisting is possible and ought to be used:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC';
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe

How to prevent SQL Injection in parameters with CakePHP

How to prevent SQL Injection while fetching data from the database when using parameters received from the user input:
if(isset($_GET['cityval']) && $_GET['cityval'] !=''){
$city = $this->request->query('cityval');
$searching .= " and college_city in ($city) ";
} else {
$searching .= "";
}
if(isset($_GET['scholarship']) && $_GET['scholarship'] !=''){
$searching .= " and college_scholarship = '".$_GET['scholarship']."' ";
} else {
$searching .= "";
}
And my main query is below
$search = $this->Search->query("select * from colleges where college_id!='' and status='active' $searching order by $order desc limit $start, 10 ");
Don't use raw queries. Simply use the query builder CakePHP provides, and it will prevent injection for you. See the online CakePHP book for more information.
It is SUPER rare to need to use raw queries in CakePHP.
What you try to do is obviously to search by get parameters. There is a wonderful plugin that makes it pretty easy https://github.com/FriendsOfCake/search
It could be actually that easy with the plugin:
$query = $this->Colleges->find('search', [
'search' => $this->request->query
]);
$this->set('results', $this->Paginator->paginate($query));
The search params itself will be handled in the model layer, check the plugins documentation on that. And the framework will take care of sanitizing the input.
It seems that Cake ORM uses PDO:
Underneath the covers, the query builder uses PDO prepared statements
which protect against SQL injection attacks.
Reference: https://book.cakephp.org/3.0/en/orm/query-builder.html
Unfortunately the way you're creating the query is vulnerable as you're not using Cake ORM neither PDO prepared statements.
If you want to use raw queries you could do something like this to protect your code:
// Add this in the beginning of the file/code:
use Cake\Datasource\ConnectionManager;
// Replace connection_name with the name of your connection (maybe it's "default")
$connection = ConnectionManager::get('connection_name');
$bindList = [];
$city = $this->request->query('cityval');
// PDO as a limitation for the parameter markers. See in the comments below
$cityList = array_filter(explode(',', $city), function($item) {
return preg_match('/^\d+$/', $item);
});
$csvCity = implode(',', $cityList);
$scholarship = $this->request->query('scholarship');
if (!empty($csvCity)) {
$searching .= " and college_city in ($csvCity)";
}
if (!empty($scholarship)) {
$searching .= " and college_scholarship = :scholarship";
$bindList['scholarship'] = $scholarship;
}
$stmt = $connection->prepare($searching);
$stmt->bind($bindList);
$stmt->execute();
// Read all rows.
$rows = $stmt->fetchAll('assoc');
// Read rows through iteration.
foreach ($rows as $row) {
// Do work
}
PDO has a limitation and because of that there's no proper way to use the SQL IN() clause in a prepared statement (to bind the values to it), so we need to parse manually the values to be inside that clause as I did in the code.
From the PDO Prepare manual page:
Note: Parameter markers can represent a complete data literal only.
Neither part of literal, nor keyword, nor identifier, nor whatever
arbitrary query part can be bound using parameters. For example, you
cannot bind multiple values to a single parameter in the IN() clause
of an SQL statement.
References
CakePHP 3.3 Cookbook - Database basics
PHP Manual - PHP Data Objects
PHP The Right Way

PHP prepared statements clarification

Can you mix user input data with fixed data in a prepared statement security wise or does each query condition have to have a placeholder?
For example:
$code = htmlspecialchars($_GET['code']); // USER INPUT DATA
$status = 'A'; // FIXED
$stmt = $connect->prepare("SELECT s_id FROM events WHERE s_code = ? AND s_status = ?") or die(mysqli_error());
$stmt->bind_param('ss', $code, $status);
$stmt->execute();
$stmt->bind_result($reference);
Or is this also acceptable?
$code = htmlspecialchars($_GET['code']); // USER INPUT DATA
$stmt = $connect->prepare("SELECT s_id FROM events WHERE s_code = ? AND s_status = 'A'") or die(mysqli_error());
$stmt->bind_param('s', $code);
$stmt->execute();
$stmt->bind_result($reference);
Both approaches are acceptable. Obviously there's no security impact in binding a fixed value from your code, but it may have some performance benefits if various parts of your application (or even different applications) use different hard-coded values for that query.
To complement the answer provided by Mureinik, you should also focus on the user input a bit. Prepared statements are effective at preventing SQL injection attacks, but they are not a universal antidote against all types of attacks.
Judging by your example I would say you expect the $_GET['code'] to be an integer. As an extra layer of security you can (and should) sanitize and also validate the user input. Something along these lines:
// avoid accessing directly super-globals like $_GET, $_POST
// #see Sanitize filters: http://nl1.php.net/manual/en/filter.filters.sanitize.php
$code = filter_input(INPUT_GET, 'code', FILTER_SANITIZE_NUMBER_INT);
// #see Validate filters: http://nl1.php.net/manual/en/filter.filters.validate.php
$options = array(
'options' => array(
'min_range' => 1,
'max_range' => 1000000,
));
if (!filter_var($code, FILTER_VALIDATE_INT, $options)) {
echo 'Invalid code!';
}

Code for Updating MySQLI PHP

A few keep telling me that my code for updating data in my mysqli query is extremely insecure. Actually, several people on this site. So I would like to know what they say would secure my code below so it is secure when updating my database. I would like to know how the would secure my mysqli query.
Okay, in my code for my database entries, this is what I do. Let me start by saying that I always send via POST method to avoid browser url complications.
When I get the POST data, this is my code.
$ID = 1;
$DATA = htmlentities(addslashes($_POST['data']));
$FIELD = "lifename";
$DBQUERY = "UPDATE `lifetable` SET `$FIELD` = '$DATA' WHERE `id` = $ID";
$DBRESULT = $MYSQLI->query($DBQUERY);
I am currently using this on my local site.
How is this unsafe if I have escaped all quotes, all slashes, all ampersands (from javascript through ajax) and all semi colons? How is this vunerable?
So can you tell me what I should change when adding information to my database.
Thanks
PS ... I am using mysqli and will continue to use it. Thanks
A few suggested that I change from mysqli to pdo, but I am not willing to completely 100% change how I access data from my databases. Someone posted another link before about prepare and bind_param and this is what I am going to use. So thank you.
This is now my code, and binding params is supposed to make it so that each param is only for the one part of my query and can not be for anything else, nothing else at all.
$DBQUERY = "UPDATE `lifetable` SET `lifename` = ? WHERE `id` = ?"; // EACH ? IS A PART OF bind_param BELOW IN ORDER AFTER TYPE.
$STMT = $MYSQLI->prepare($DBQUERY);
$STMT->bind_param('si', $DATA, $ID); // THIS MAKES SURE THAT THE VARIABLES ARE ONLY USED FOR THERE PLACE HERE AND NOTHING ELSE. ? in order.
$DATA = htmlentities($_POST['data']); // I STILL USE MY CODE HERE TO REMOVED ANY OTEHR CHARACTERS, JUST INCASE. AND BEFORE IT GETS HERE, IT USES encodeURIComponent TO OUTPUT FROM AJAX.
$ID = $COLUMN[1];
$STMT->execute();
$STMT->close();
My code worked before and it works now, just more secure, or so I am told.
Use PDO Class like:
$db = new PDO('mysql:host=localhost;dbname=<SOMEDB>', '<USERNAME>', 'PASSWORD');
$query = $db->prepare('UPDATE `lifetable` SET :FIELD = :DATA WHERE `id` = :ID');
$query->execute(array(
':FIELD' => $field,
':DATA' => $data,
':ID' => $id
));
$query->commit();
For more info Are there good tutorials on how to use PDO?
i think your security lies in the SQL injection, and the best way i know to make the query secure is using mysql_real_escape_string on the var. Here an example taken from php.net
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
$city = $mysqli->real_escape_string($city);
$mysqli->query("INSERT into myCity (Name) VALUES ('$city')")
you can apply the same procedure to your query
$ID = 1;
$DATA = $MYSQLI->real_escape_string($_POST['data']));
$FIELD = "lifename";
$DBQUERY = "UPDATE `lifetable` SET `$FIELD` = '$DATA' WHERE `id` = $ID";
$DBRESULT = $MYSQLI->query($DBQUERY);
I edited the above because I forgot the quotes for lifename in my question. They should be there as they are in my original code.
now tour query should be secure :D
here the reference to php.net documentation :
http://cn2.php.net/manual/en/mysqli.real-escape-string.php

Categories