Part of the EllisLab Network
   
1 of 3
1
Vulnerable bug in CodeIgniter which took us hours to fix our corrupted database
Posted: 18 April 2007 10:20 AM   [ Ignore ]  
Summer Student
Avatar
Total Posts:  25
Joined  03-05-2007

I use codeigniter internally to develop our web solutions for somewhere in… net limited, a Norwegian company. Day before yesterday we suffered a terrible situation for an internal bug in code igniter which corrupted data inside some tables of our application database and then it tooks hours to find the origin of that bug, to fix it and to repair the corrupted data. Let me explain what happened.

Lets guess that we have one table named “users” with the following field

1. id
2. username
3. password
4. email

At some point, if you want to update the password field of this table, for a particular user, what will you write in your code?

$data = array("password"=>$new_password);
$this->db->where("id",$user_id);
$this->db->update("users", $data);

CodeIgniter’s ORM will create the query like the following

UPDATE users set password='{$new_password}' where user_id='{$user_id}';

Well, it’s ok and the quesry seems pretty fine. Now what should happen if you pass a valid user id to this code? Password of only that user will be updated. But what will happen when the passed $user_id is null?? Thats the most pathetic part that Codeigniter ORM plays. Instead of generating the following query,

UPDATE users set password='{$new_password}' where user_id=;

CodeIgniter’s ORM actually generates the following

UPDATE users set password='{$new_password}' where user_id;

You find the difference of the above two queries right? one contains “where user_id=’‘ ” and another contains just “where user_id” . Now if your backend database is MySQL and this query executes? You know what the hell will happen? It will replace all the user’s password with this new password instead of failing as MySQL count the “where user_id” part equals to false and returns all users. But If your Database is PostgreSQL, it fails, you are lucky.

So day before yesterday we suffered this problem against our commercial application which corrupts our user profile data. We immediate fixed the issue from our backup db (well, we lost 3 data) and then we started to find out what actually went wrong and found this vulnerable bug in CI.

So we suggest the CodeIgniter team to fix the issue immediately and change their ORM code so that it creates the query like the following if the value of passed argument is null. because it will fail to execute in all db. Otherwise the fellow user’s of code igniter, prepare for the dooms day.

UPDATE users set password='{$new_password}' where user_id=;

 Signature 

Regards
Hasin Hayder
Zend Certified Engineer
Pageflakes Limited

See my blog at http://hasin.wordpress.com

Profile
 
 
Posted: 18 April 2007 10:58 AM   [ Ignore ]   [ # 1 ]  
Summer Student
Total Posts:  6
Joined  03-23-2007

Now maybe this isn’t the expected behaviour you wanted, and the opinion will vary from person to person but CI can only work with what you give it, and (not to be an ass) but that value should have been checked against being null before it ever got to any kind of SQL statement regardless of how the ActiveRecord class dealt with it. ActiveRecord does no validation or checking. Now again, yes, maybe it should be changed and should error, but you can hardly blame this on CI and classify it as a “bug”. Though it is not stated in the User Guide what it does with null values in this case (and do you mean null as NULL, or null as in an empty string?), and that is probably something at the least that should be changed to prevent anyone else from having the same problem.

Again, only my opinion.

Profile
 
 
Posted: 18 April 2007 11:06 AM   [ Ignore ]   [ # 2 ]  
Summer Student
Avatar
Total Posts:  25
Joined  03-05-2007
tehasdf - 18 April 2007 10:58 AM

Now maybe this isn’t the expected behaviour you wanted, and the opinion will vary from person to person but CI can only work with what you give it, and (not to be an ass) but that value should have been checked against being null before it ever got to any kind of SQL statement regardless of how the ActiveRecord class dealt with it. ActiveRecord does no validation or checking. Now again, yes, maybe it should be changed and should error, but you can hardly blame this on CI and classify it as a “bug”. Though it is not stated in the User Guide what it does with null values in this case (and do you mean null as NULL, or null as in an empty string?), and that is probably something at the least that should be changed to prevent anyone else from having the same problem.

Again, only my opinion.

 

You mis interpreted my speech. I agree with you cent persent,  and thats why I tell that CI should generate the query with exactly what I give it to it. And thats why codeigniter should not generate the following query

UPDATE users set password='{$new_password}' where user_id;

But this one

UPDATE users set password='{$new_password}' where user_id=;

as because I supplied “null” as user_id. Then the query will fail gracefully and application will work perfectly. But what code igniter does, it neglects the param when it is null which results a tremendous “What-The-Hell?” type problem.

Regards
Hasin Hayder

 Signature 

Regards
Hasin Hayder
Zend Certified Engineer
Pageflakes Limited

See my blog at http://hasin.wordpress.com

Profile
 
 
Posted: 18 April 2007 11:07 AM   [ Ignore ]   [ # 3 ]  
Grad Student
Avatar
Rank
Total Posts:  56
Joined  05-10-2006

That’s not a bug. You should be checking to make sure you have a user_id before executing any statements. The framework did exactly what it says it will do.

It isn’t a bug and it isn’t a vulnerability.

Profile
 
 
Posted: 18 April 2007 11:09 AM   [ Ignore ]   [ # 4 ]  
Summer Student
Avatar
Total Posts:  25
Joined  03-05-2007
CI David-CSD - 18 April 2007 11:07 AM

That’s not a bug. You should be checking to make sure you have a user_id before executing any statements. The framework did exactly what it says it will do.

It isn’t a bug and it isn’t a vulnerability.

If it is not a bug, it should generate this one

UPDATE users set password='{$new_password}' where user_id=;

 Signature 

Regards
Hasin Hayder
Zend Certified Engineer
Pageflakes Limited

See my blog at http://hasin.wordpress.com

Profile
 
 
Posted: 18 April 2007 11:14 AM   [ Ignore ]   [ # 5 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  718
Joined  02-05-2007

I don’t think you can defend CI for this one. This is definitely a bug.

 Signature 

“I am the terror that flaps in the night”

Profile
 
 
Posted: 18 April 2007 11:15 AM   [ Ignore ]   [ # 6 ]  
Grad Student
Avatar
Rank
Total Posts:  56
Joined  05-10-2006

You could submit that as a feature request and see if the default behavior can be modified to work as you suggest.

If you would have been validating your data to ensure you could properly execute the statement in the first place, it wouldn’t be an issue. You may have a point but in my opinion you should always make sure your data is valid before trying to execute SQL statements or things could go very badly.

Profile
 
 
Posted: 18 April 2007 11:21 AM   [ Ignore ]   [ # 7 ]  
Summer Student
Avatar
Total Posts:  25
Joined  03-05-2007
CI David-CSD - 18 April 2007 11:15 AM

You could submit that as a feature request and see if the default behavior can be modified to work as you suggest.

If you would have been validating your data to ensure you could properly execute the statement in the first place, it wouldn’t be an issue. You may have a point but in my opinion you should always make sure your data is valid before trying to execute SQL statements or things could go very badly.

I agree with you David, As long as you are actually meaning what you said. I agree with you that I must validate the data before passing to CI (if I did it that time, i wouldnt suffer it, but…) and I strongly disagree with what CI does to it. If I pass null, CI should treat it as null and keep the ”=” sign in the query, not by eliminating that ”=” which changes the meaning of whole query.

 Signature 

Regards
Hasin Hayder
Zend Certified Engineer
Pageflakes Limited

See my blog at http://hasin.wordpress.com

Profile
 
 
Posted: 18 April 2007 11:23 AM   [ Ignore ]   [ # 8 ]  
Summer Student
Total Posts:  6
Joined  03-23-2007

It is not a bug so much as the behaviour is not described in the documentation what it would do in this situation (for instance, if this was in the documentation, there would be no need for this post as that behaviour would be expected). From looking at the active record code, it looks like this only occurs if the value is NULL (data type NULL or missing parameter), an empty string should produce the expected code of where=.

If you want a quick fix, open the DB_active_rec.php, find the _where method and change it to:

function _where($key, $value = NULL, $type = 'AND ')
    
{
        
if ( ! is_array($key))
        
{
            $key
= array($key => $value);
        
}
          
        
foreach ($key as $k => $v)
        
{
            $prefix
= (count($this->ar_where) == 0) ? '' : $type;
            
                if ( !
$this->_has_operator($k))
                
{
                    $k
.= ' =';
                
}
            
                $v
= ' '.$this->escape($v);
                        
            
$this->ar_where[] = $prefix.$k.$v;
        
}
        
return $this;
    
}

That should work (no promises). Basically removed the if statment checking if it’s null.

Profile
 
 
Posted: 18 April 2007 11:28 AM   [ Ignore ]   [ # 9 ]  
Grad Student
Avatar
Rank
Total Posts:  56
Joined  05-10-2006
I agree with you David, As long as you are actually meaning what you said.

Certainly. Not looking to argue at all here. In fact I think you should definitely make a feature request for that as it certainly wouldn’t hurt to have a safety net.

Profile
 
 
Posted: 18 April 2007 11:55 AM   [ Ignore ]   [ # 10 ]  
Summer Student
Avatar
Total Posts:  25
Joined  03-05-2007
CI David-CSD - 18 April 2007 11:28 AM
I agree with you David, As long as you are actually meaning what you said.

Certainly. Not looking to argue at all here. In fact I think you should definitely make a feature request for that as it certainly wouldn’t hurt to have a safety net.


Thanks David. I eagerly want this one to be added as a Fix (or feature) in CI. Or this behavior should be documented pretty well.

 Signature 

Regards
Hasin Hayder
Zend Certified Engineer
Pageflakes Limited

See my blog at http://hasin.wordpress.com

Profile
 
 
Posted: 18 April 2007 01:19 PM   [ Ignore ]   [ # 11 ]  
Lab Assistant
RankRank
Total Posts:  128
Joined  04-06-2007

I have to agree with the OP here that this should be called a bug.  While it is not ActiveRecord’s job to filter and check the data, it is ActiveRecord’s job to create the query with the data I gave it.  If I gave it a null value, that should be reflected in the query.

This query does not reflect that I gave a null value as it does not compare the field user_id to null, or nothing, etc:

UPDATE users set password='{$new_password}' where user_id;

Profile
 
 
Posted: 18 April 2007 01:47 PM   [ Ignore ]   [ # 12 ]  
Summer Student
Total Posts:  25
Joined  12-28-2006

I am surprised nobody has asked for ActiveRecord to generate ‘where userid IS NULL’ instead of ‘where userid=’ since NULL values actually can be useful while designing automated processes and people may want that possibility available. In the case of updating passwords, I would hope that no users had a null userid, and the query just wouldn’t occur.

Profile
 
 
Posted: 18 April 2007 02:00 PM   [ Ignore ]   [ # 13 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  732
Joined  10-18-2006

I don’t think this is a bug, but I don’t think this is the expected behaviour.

In this case I think query should by

UPDATE users set password='{$new_password}' where user_id IS NULL;

 Signature 

Once in a while I remember I use Twitter

Profile
 
 
Posted: 18 April 2007 02:04 PM   [ Ignore ]   [ # 14 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  197
Joined  04-18-2006

I agree this should be fixed. I ran into it but I didn’t mind so much… I don’t like to put all of my trust into sql-generating code anyways. Anytime I’m doing an update/delete type of operation, I always check the values going in that CANNOT be empty/null, as my application should dictate. So a quick sanitizing check at the top of the model method is good insurance:

function delete($id)
{
  
// $id empty/0/null? don't even try
  
if(empty($id))
    return
false;

  
// continue with SQL stuff

}

 Signature 

http://www.motortopia.com/
http://www.phpinsider.com/

Profile
 
 
Posted: 18 April 2007 03:18 PM   [ Ignore ]   [ # 15 ]  
Lab Technician
Avatar
RankRankRankRank
Total Posts:  1735
Joined  06-23-2006
Seppo - 18 April 2007 02:00 PM

I don’t think this is a bug, but I don’t think this is the expected behaviour.

In this case I think query should by

UPDATE users set password='{$new_password}' where user_id IS NULL;

I call it a bug, but also agree this should be the outcome. A null value is valid in a database, but with the Active Record class, it was being used to conditionally affect how the query was composed.

 Signature 

Mac OS X 10.4.10, Apache 1.3.3, PHP 5.2.3, CodeIgniter 1.5.x., baby!

Profile
 
 
   
1 of 3
1
 
Post Marker Legend
New Topic New posts Hot Topic Hot Topic with new posts New Poll New Poll Moved Topic Moved Topic Sticky Topic Sticky topic
Old Topic No new posts Hot Old Topic Hot Topic with no new posts Old Poll Old Poll Closed Topic Closed Topic Announcement Announcements
Theme
Change Theme
Visitor Statistics
The most visitors ever was 719, on June 06, 2008 10:16 AM
Total Registered Members: 62792 Total Logged-in Users: 19
Total Topics: 77479 Total Anonymous Users: 0
Total Replies: 418199 Total Guests: 159
Total Posts: 495678    
Members ( View Memberlist )
Newest Members:  markrichesongerdyPorscheescapeexpyAnn BaileyTy BexDamien2k8cibbuserphilcalvin