codenigiter: sql injection and xss_clean - codeigniter

I am using active record in codenigiter to do some query and I read some docs that say using AR will escape the parameter automaticly.I want to comfirm this and I read the source code of AR class,but I am confused!
I do some test,eg,I access the url as follow is:
http://wrecruit.tudouya.com/company/editProfile/4
then I enable the profiler in CI.
when I add a single quote at the end of url as follows:
http://wrecruit.tudouya.com/company/editProfile/4'
I see the real sql statement the query execute and I got this:
SELECT *
FROM (`wy_company`)
WHERE `id` = '4%27'
the single quote is escaped to '%27',I want to know how this escape happen?maybe it's escaped by the input class?

Url adress is always encoded with urlencode function. This function replace all symbols with codes.
If you want to prevent xss you should to check you parameter. May be like this (in controller Company):
public function editProfile($id)
{
$id = (int)$id;
if($id){
// model code execute - loading DB data
}
}
And in DB query you should use Query Bindings, or use Active record. Them both are prevent injection.

Related

Insert using a raw SQL query to avoid SQL injection?

I have personalized tables and a bunch of composite keys in my database so I am using raw SQL queries to perform the CRUD operations needed. I found a way to make an insert following the documentation and it worked, but I am wondering, isn't this method vulnerable to SQL injection? I am using the user's input to insert this data and I don't see where's the sanitization of it, maybe I am just wrong though. Can you guide me? Here's my code:
public function store(Request $request)
{
/*No composite keys here so I am using Eloquent*/
$song = new Song();
$song->code = $request->code;
$song->title = $request->title;
$song->artist = $request->artist;
$song->length = $request->length;
$song->album = $request->album;
$song->save();
$genre = new Genre();
$genre->id_gen = $request->genre;
$genre->id_song = $request->code;
DB::insert('INSERT INTO genres (id_gen, id_song) values (?, ?)', [$genre->id_gen, $genre->id_song]);
return $song;
}
Using an insert in this fashion does not mean a SQL injection risk as this is what is known as a parameterized query. You are generating a query as a string, and then the database system performs its own properly managed replacements to construct the query. I can't recall if this is done at the database or driver level.
What you have done is exactly what Laravel does internally anyway (construct parameterized queries).
In terms of your actual code, you're doing something a little odd. By creating the Genre object, applying your request to it and saving, you're doing an insert anyway. There is no real need for the raw insert;
Be sure to validate your request object!
The query uses placeholders (in other words the query-string can be stored as a template or as a constant).
This gives the sql-engine a chance to convert the query to a prepared-statement.
I do not have any knowledge of laravel but this looks like a legitimate use of prepared statements (and consequently immune to sql injection).
In other words the approach looks safe (atleast w.r.t sql-injection).

$this->db->escape() function adding single quote in codeigniter

In codeigniter when i am using function $this->db->escape() while insert data, It is adding single quote in database, Can anyone please help why i am getting this issue ?
Here is my code
$data = array('company_id'=>$this->db->escape($companyID),'payor_type'=>$this->db->escape($payor_type),
'payer_type'=>$this->db->escape($payer_type),'insurance'=>$this->db->escape($insurance),
'created_date'=>date("Y-m-d H:i:s"));
$this->db->insert('tb_Payer',$data);
When you use the query builder class to construct your queries the values are escaped automatically by the system so you don't have to use the function $this->db->escape. In your case, each value was escaped by the escape function and the system did it again for each value when executing the insert function.
Now if you want to run custom queries using the function $this-db->query it is a good practice to escape the data like bellow:
$sql = "INSERT INTO table (column) VALUES(".$this->db->escape($value).")";
$this->db->query($sql);

Zend DbTable case insensitive

I have a login system for my webapp that works well using the Zend auth adapter but the problem is I want the email to be case insensitive when a user logs in. I am using Oracle as the back end DB and normally I would user the LOWER(EMAIL)=LOWER(:email) method. I tried to pass that Oracle function in the setIdentityColumn() but I get the error:
The supplied parameters to Zend_Auth_Adapter_DbTable failed to produce
a valid sql statement, please check table and column names for
validity.
protected function _getAuthAdapter()
{
//$dbAdapter = Zend_Db_Table::getDefaultAdapter();
$db = Zend_Registry::get('db');
$authAdapter = new Zend_Auth_Adapter_DbTable($db);
$authAdapter->setTableName('USER_TABLE')
->setIdentityColumn('LOWER(EMAIL)') //Tried to pass LOWER()
->setCredentialColumn('ENCODED_PW')
->setCredentialColumn('PASSWORD');
return $authAdapter;
}
The error is coming from the function _authenticateCreateSelect() in the Zend_Auth_Adapter_DbTable class. The problem is this part of the script:
$dbSelect->from($this->_tableName, array('*', $credentialExpression))
->where($this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?', $this->_identity);
The quoteIdentifier() method is like PHP quote() and is turning a query like this:
select * from LOWER(:email)
into this:
select * from "LOWER(:email)"
Anyone see a way around this?
Kind Regards
Nathan
Try something like this:
$authAdapter->setTableName('USER_TABLE')
->setIdentityColumn(new Zend_Db_Expr('LOWER(USERID)'))
->setCredentialColumn('PASSWORD');
The problem is that if you pass 'LOWER(USERID)' as a simple string, Zend will put quotes around it, causing it to create an invalid query. Using Zend_Db_Expr will stop Zend doing this.

ActiveRecord search returns 'Syntax error or access violation' error

In my Yii application, I have a model that represents siteconfig table and have four columns:
integer config_id,
string key,
string value,
string update_time.
I created a model using Gii (to ensure that I will not make any mistakes). I don't publish entire code here, cause this is 100% unmodified by me, standard model code generated by Gii. Since my problem is related to search, I only publish important part of generated code (the search() method):
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('config_id',$this->config_id);
$criteria->compare('key',$this->key,true);
$criteria->compare('value',$this->value,true);
$criteria->compare('update_time',$this->update_time,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
I'm trying to use generated model in normal Yii ActiveRecord search like that:
$etona = new SiteConfigurationRecord();
$crit = new CDbCriteria();
$crit->select = "value";
$crit->condition = "key=:key";
$crit->params = array(":key"=>"sitename");
$etona = $etona->find($crit);
But, instead of getting expected search results, a strange (for me) error occurs:
CDbCommand failed to execute the SQL statement: SQLSTATE[42000]:
Syntax error or access violation: 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 'key='sitename' LIMIT 1' at line 1.
The SQL statement executed was: SELECT value FROM siteconfig t
WHERE key=:key LIMIT 1
Where did I go wrong?
You used key for column name, which is a reserved word in MySQL. Yii uses table alias in queries, but does not take any special care in case of reserverd word used as columns names. So, you have to take care of this by yourself.
For example:
$etona = new SiteConfigurationRecord();
$crit = new CDbCriteria();
$crit->select = "value";
$crit->condition = "t.key=:key"; // 't' is default alias
$crit->params = array(":key"=>"sitename");
$etona = $etona->find($crit);
This should solve your problem.
As #Dmitry explained, SQL doesn't allow you to use the column name key. The Yii call in the code in your answer works because Yii performs parameter binding automatically, using names other than reserved words for the parameters. And it also uses fully-qualified column names (prefixes all column name references with <tablename>., regardless of what invalid column name (reserved words) you pass the findByAttributes method.
now it works.. ^^
i just use this code...
$etona = SiteConfigurationRecord::model()->findByAttributes(array('key'=>'sitename'));
maybe i need to study activerecord more somehow...
but still i don't know why the code above doesn't work

How to use 'IN (1,2,3)' with findAll?

I need to get a couple of Students from the database, and I have their primary keys in a comma-separated string.
Normally using SQL it would be something like:
$cleanedStudentIdStringList = "1,2,3,4";
SELECT * FROM Student WHERE id IN ($cleanedStudentIdStringList)
Yii's ActiveRecord seems to insert a single quote around bound parameters in the resulting SQL statement which cause the query to fail when using parameter binding.
This works, but doesn't use safe parameter binding.
$students = Student::model()->findAll("id IN ({$_POST['studentIds']})");
Is there a way to still use parameter binding and get only a couple of rows in a single query?
You can do it also that way:
$criteria = new CDbCriteria();
$criteria->addInCondition("id", array(1,2,3,4));
$result = Student::model()->findAll($criteria);
and use in array any values you need.
Aleksy
You can use findAllByAttributes method also:
$a=array(1,2,3,4);
$model = Student::model()->findAllByAttributes(array("id"=>$a));

Resources