Seguridad

Principios guía

Validación de formularios

Validación del cliente

Es preferible realizar una validación inicial en el lado del cliente para evitar enviar datos no válidos al servidor.

Ejemplo de creación de un formulario en la acción de un controlador (esta parte podría ubicarse en un servicio dedicado para una mejor separación de capas):

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 }

La Vista Asociada:

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

Nota

Los controladores CRUD integran automáticamente esta validación del lado del cliente utilizando los validadores adjuntos a los miembros de los modelos.

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

Validación en el servidor

Es preferible restringir las URL autorizadas a modificar los datos.
Previamente, especificando el método Http en las rutas, y probando la petición :

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

Nota

El módulo Ubiquity-security ofrece un control adicional para evitar las peticiones cross-site.

Tras modificar un objeto, es posible comprobar su validez, dados los validadores adjuntos a los miembros del Modelo asociado:

#[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...
      }
   }
}

Operaciones DAO

Siempre se recomienda utilizar consultas parametrizadas, independientemente de las operaciones que se realicen con los datos:
  • Para evitar inyecciones SQL.

  • Permitir el uso de consultas preparadas, acelerando el procesamiento.

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

Nota

Las operaciones DAO que toman objetos como parámetros utilizan este mecanismo por defecto.

DAO::save($user);

Gestión de contraseñas

El transformador Contraseña permite que un campo sea de tipo contraseña cuando se muestra en un formulario CRUD generado automáticamente.

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

Tras el envío desde un formulario, es posible encriptar una contraseña desde la clase URequest:

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

El algoritmo utilizado en este caso está definido por el PASSWORD_DEFAULT de php.

También es posible comprobar una contraseña introducida por un usuario del mismo modo, para compararla con un hash:

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

Importante

Configure Https para evitar el envío de contraseñas en texto claro.

Módulo de seguridad/gestión ACL

Además de estas pocas reglas, puede instalar si es necesario: