Sécurité

Principes directeurs

Validation des formulaires

Validation côté client

Il est préférable d’effectuer une validation initiale côté client pour éviter de soumettre des données invalides au serveur.

Exemple de la création d’un formulaire dans l’action d’un contrôleur (cette partie pourrait être située dans un service dédié pour une meilleure séparation des couches) :

app/controllers/UsersManagement.php
 1 public function index(){
 2     $frm=$this->jquery->semantic()->dataForm('frm-user',new User());
 3     $frm->setFields(['login','password','connection']);
 4     $frm->fieldAsInput('login',
 5         ['rules'=>'empty']
 6     );
 7     $frm->fieldAsInput('password',
 8         [
 9             'inputType'=>'password',
10             'rules'=>['empty','minLength[6]']
11         ]
12     );
13     $frm->setValidationParams(['on'=>'blur','inline'=>true]);
14     $frm->fieldAsSubmit('connection','fluid green','/submit','#response');
15     $this->jquery->renderDefaultView();
16 }

Ma vue associée :

app/views/UsersManagement/index.html
 {{ q['frm-user'] | raw }}
 {{ script_foot | raw }}
 <div id="response"></div>
../_images/frm-user.png

Note

Les contrôleurs CRUD intègrent automatiquement cette validation côté client en utilisant les validateurs attachés aux membres des modèles.

#[Column(name: "password",nullable: true,dbType: "varchar(255)")]
#[Validator(type: "length",constraints: ["max"=>20,"min"=>6])]
#[Transformer(name: "password")]
private $password;

Validation côté serveur

Il est préférable de restreindre les URLs autorisées à modifier les données.
Au préalable, en spécifiant la méthode Http dans les routes, et en testant la requête :

#[Post(path: "/submit")]
public function submitUser(){
   if(!URequest::isCrossSite() && URequest::isAjax()){
      $datas=URequest::getPost();//post with htmlEntities
      //Do something with $datas
   }
}

Note

Le module Ubiquity-security offre un contrôle supplémentaire pour éviter les requêtes intersites.

Après avoir modifié un objet, il est possible de vérifier sa validité, grâce aux validateurs attachés aux membres du Modèle associé :

#[Post(path: "/submit")]
public function submitUser(){
   if(!URequest::isCrossSite()){
      $datas=URequest::getPost();//post with htmlEntities
      $user=new User();
      URequest::setValuesToObject($user,$datas);

      $violations=ValidatorsManager::validate($user);
      if(\count($violations)==0){
         //do something with this valid user
      } else {
         //Display violations...
      }
   }
}

Opérations DAO

Il est toujours recommandé d’utiliser des requêtes paramétrées, quelles que soient les opérations effectuées sur les données :
  • Pour éviter les injections SQL.

  • Pour permettre l’utilisation de requêtes préparées, accélérant le traitement.

$googleUsers=DAO::getAll(User::class,'email like ?',false,['%@gmail.com']);
$countActiveUsers=DAO::count(User::class,'active= ?',[true]);

Note

Les opérations DAO qui prennent des objets comme paramètres utilisent ce mécanisme par défaut.

DAO::save($user);

Gestion des mots de passe

Le transformateur Password permet à un champ d’être du type mot de passe lorsqu’il est affiché dans un formulaire CRUD généré automatiquement.

#[Transformer(name: "password")]
private $password;

Après soumission d’un formulaire, il est possible de crypter un mot de passe à partir de la classe URequest :

$encryptedPassword=URequest::password_hash('password');
$user->setPassword($encryptedPassword);
DAO::save($user);

L’algorithme utilisé dans ce cas est défini par le paramètre php PASSWORD_DEFAULT.

Il est également possible de vérifier de la même manière un mot de passe saisi par un utilisateur, en le comparant à un hachage :

if(URequest::password_verify('password', $existingPasswordHash)){
   //password is ok
}

Important

Configurez Https pour éviter d’envoyer les mots de passe en clair.

Module de sécurité/ Gestion des ACL

En plus de ces quelques règles, vous pouvez procéder à des installations si nécessaire :