Bonjour,
pendant le développement d'un de mes projet, un amis ma fait constater une faille sur un de mes formulaire et propre à cakePHP.
Je me suis dis pourquoi ne partager ce problème. Noté que ce sujet à peut être déjà été abordé sur d'autres forum.
La faille concerne :
Dans le cas d'un Ajout ou d'un Edit via un formulaire avec cake.
Cette faille permet à un autre utilisateur de prendre possession du billet.
Injection d'un bout de code html dans une page formulaire.
Ma table billet :
id
content
user_id
Voici la fonctionnalité Edit du cookbook, elle peut bien entendu être plus complexe, plus sécurisé. Le but ici est de vous expliquer le mécanisme.
fonction edit($id = null) {
$this->Post->id = $id;
if (empty($this->data)) {
$this->data = $this->Post->read();
// VERIFICATION PROPRIETE.
} else {
$this->data'Query']'user_id'] = $_SESSION'Auth']'User']'id']; // Associer le billet à utilisateur connecté
if ($this->Post->save($this->data)) {
$this->Session->setFlash('Your post has been updated.');
$this->redirect(array('action' => 'index'));
}
}
}
User 1 veut crée un nouveau billet voici sont déroulement :
User 1 charge la page du formulaire.
Vu que $id = null, il fourni un formulaire blanc.
User 1 rempli le formulaire et l'envoie au serveur.
function edit($id = null) {
$this->Post->id = $id;
// $this->data n'est pas vide ==> ELSE.
if (empty($this->data)) {
$this->data = $this->Post->read();
// VERIFICATION PROPRIETE.
if($this->data'Billet']'user_id'] == $_SESSION'Auth']'User']'id']
} else {
$this->data'Query']'user_id'] = $_SESSION'Auth']'User']'id']; // Associer le billet à utilisateur connecté
// EXECUTION DU CODE, sauvegarde du billet.
if ($this->Post->save($this->data)) {
$this->Session->setFlash('Your post has been updated.');
$this->redirect(array('action' => 'index'));
}
}
}
Nous avons à présent dans notre base un billet :
Id : 536
content : « Salut les gens »
user_id : 1 //user_id 1
Maintenant nous avons User 2 qui veut prendre possession du billet, grâce par exemple à la view du billet, il sais que id du billet vaut 536
Cependant User2 ne peu pas effacer le billet 536 car il ne possède par les droit sur celui-ci.
User2 charge le formulaire Edit pour crée un nouveau billet :
Voici le code html :
<textarea id="BilletBillet" rows="6" cols="30" name="data[Billet][Content]"></textarea>
grâce à édition via par exemple firebug de Mozilla, il va éditer sa page formulaire pour rajouter un nouveau champ, soit id:
<input id="BilletBillet" type="text" name="data[Billet][id]" maxlength="255">
<textarea id="BilletBillet" rows="6" cols="30" name="data[Billet][Content]"></textarea>
Maintenant il lui suffis de mettre id du billet qu'il veut usurper et un contenu gens « Je prend ton billet » !
Il poste le messages.
Retour au code EDIT, que ce passe t-il.
Pour cela je vais vous donner la structure du $->data'Billet'].
$this->data->'Billet']'id'] = 536.
$this->data->'Billet']'content'] = « Je prend ton billet » .
Dans Edit:
function edit($id = null) {
$this->Post->id = $id;
// Le champs data n'est pas vide, il contient id & le content => ELSE
if (empty($this->data)) {
$this->data = $this->Post->read();
// VERIFICATION PROPRIETE.
} else {
$this->data'Query']'user_id'] = $_SESSION'Auth']'User']'id']; // Associer le billet à utilisateur connecté, soit User 2.
// Maintenant c'est ici que ça fache, id du billet étant déclarer, cakephp detecte un update plutot d'un insert, il va mettre à jours le billet 536 en écrasant content et user_id
if ($this->Post->save($this->data)) {
$this->Session->setFlash('Your post has been updated.');
$this->redirect(array('action' => 'index'));
}
}
}
Le billet change de mains, User2 à pris possession.
Nous avons à présent dans notre base un billet :
Id : 536
content : « Je prend ton billet »
user_id : 2 //user 2 à pris possession.
Pour ma part, pour contrer cette faille je fait une vérfication avant de faire un save.
if(isset($this->data'Billet']'id'] ))
{
$check = $this->Query->find('count', array('conditions' => array('Billet .id' => $this->data'Billet']'id'], 'Billet .user_id' => $_SESSION'Auth']'User']'id'])));
if( $check == 0 )
{
$this->redirect(array('action' => 'Pirate'));
}
}
Voila, si vous avez des idées pour gérée au mieux ce problème, n'hésiter pas à posté vos solutions. :)
:) Oui mais par exemple si User2 rajoute un champ
<input id="BilletBillet" type="text" name="data[Billet][user_id]" maxlength="255">
en se basant sur les convention cake, le problème reste le même.
De plus, si je ne rajoute pas $this->data'Query']'user_id'] = $_SESSION... dans l'édition, n’empêche que l'injection d'un data[Billet][id] déclenche un update du billet :)
Ouep c'est ce que j'ai fait dans mon code.
Ce billet était simplement pour partager ce problème d'insertion d'un id dans un formulaire au autre membre :)
je pense pas que ca soit vraiment un probleme si on fait le travail correctement ;)
et si on a la variable $validate et qu'on fait un $this->Model->validates() et qu'on a rajouté un champ, le formulaire passe ou y'a une erreur mais rien est affiché dans le formulaire puisque le champ ajouté via firebug n'existe plus ?
Salut flohw,
j'aurais peut être du passer par un autre exemple car cette histoire d’édition embrouille un peu, par exemple une fonction Register pour inscription d'un nouveau membres.
2 Champs :
j'ai des rules :
Donc quand je post mon formulaire il me crée un nouvelle utilisateur, avant il vérifier que email est bien un email et password not empty.
Problème, si on rajoute un champs qui comporte le id de l’utilisateur, cakephp interprète cela comme un update et non plus un insert. il met à jours le record.
<input id="UserUser" type="text" name="data[User][id]" maxlength="255">
Dans un formulaire qui ne tien pas compte de ce problème, on peu facilement usurper un compte utilisateur.
Une solution, serais lors du save limiter les champs en indiquant les champs qu'on veut sauvegarder.
if( $this->User->save(null,false,array('email','password','profile_id','group_id')) )
{
$this->__sendActivationEmail($this->User->id);
$this->redirect(array('controller'=>'Pages', 'action'=>'thanks'));
}
Problème, à moins que cela été fixer dans une dernière version de cake, celui-ci détecte avant le save si un id existe ou pas, ensuite il applique soit un insert soit un update.
Une solution que j'avais appliquer il y'a 2 mois, c'était de faire un
unset($this->data'User']'id']);
Je sais pas si c'est plus clair :)
si c'est plus clair et je vois bien le vrai problème :)
la deuxieme solution me parait bien.
je viens d'installer firebug (je suis sous mac et je me suis mis à safari ;)) et je n'ai pas trouvé pendant les 5 minutes de recherches comment insérer du code html (bon apres, l'utilisation d'une faille ou d'un JS peut peut etre le permettre) dans ce cas là effectivement, on aurait un petit probleme je pense...
envoie un mail aux developpeurs de cake pour savoir (bonne chance :-°) et si jamais tu le fais je veux bien etre tenu au caurrant ;)
flohwSDZ[le symbole magique]hotmail.fr pour me faire suivre ;)
L'idéal si tu veux faire un insert est de faire $this->data'User']'id'] = null;
Ensuite je déconseille vivement d'enregistrer à la brute les données posté dans un formulaire pour les raisons que tu évoque. L'idéal est de faire des vérifications lors de sauvegarde avec le beforeSave par exemple ou dans le controller :)
Ce qu'il faut retenir
$this->save($this->data) <= Horriblement pas sécurisé :)
Ce n'est pas une faille liée à CakePHP donc mais plutôt à la façon de concevoir le traitement des données.
Salut Grafikart,
je vais me pencher sur le beforeSave, personellement je n'est pas encore vraiment travailler avec. Sinon comme tu dis, je fait des vérification dans le controller + une limitation des champs saver avec un
$this->User->save(null,false,array('email','password','profile_id','group_id')
par exemple. Pour ce qui est du topics, je vais surement le retravailler pour mettre en avant "ce risque" du mauvaise gestion du traitement des données :) et faire partager cela à ceux qui veulent :)
Note: dans le cas d'une fonction édit qui fait à la fois effets d'ajout ou édit, sauf si je fait erreur, on ne peu pas déclarer id à null vu que c'est lui qui fait effet de insert ou update. (quoi que d'autres solutions sont tjrs envisageable)
@ flohw.
Pour changer le code html d'une page avec firebug, c'est pas bien compliquer tu lance firebug, quand tu est dans onglet "html" tu clique droit sur le code et tu fait éditer html.
Sous chrome, pareil, une fois dans le code, tu fait droit + éditer. c'est très pratique pour tester tu code mais aussi modifier par exemple le css sans devoir repasser par ton code source. :)