Module sécurité

Installation

Installer le module Ubiquity-security à partir de l’invite de commande ou des Webtools (partie Composer).

composer require phpmv/ubiquity-security

Activez ensuite l’affichage de la partie Sécurité dans les Webtools :

../_images/display-security.png

Session CSRF

La session est par défaut protégée contre les attaques CSRF via la classe VerifyCsrfToken (même sans le module Ubiquity-security). |Une instance de jeton (CSRFToken) est générée au démarrage de la session. La validité du jeton est ensuite vérifiée via un cookie à chaque requête.

../_images/security-part.png

Cette protection peut être personnalisée en créant une classe implémentant VerifySessionCsrfInterface.

app/session/MyCsrfProtection.php
class MyCsrfProtection implements VerifySessionCsrfInterface {
   private AbstractSession $sessionInstance;

   public function __construct(AbstractSession $sessionInstance) {
      $this->sessionInstance = $sessionInstance;
   }

   public function init() {
      //TODO when the session starts
   }

   public function clear() {
      //TODO when the session ends
   }

   public function start() {
      //TODO When the session starts or is resumed
   }

   public static function getLevel() {
      return 1; //An integer to appreciate the level of security
   }
}

Démarrer la protection personnalisée dans les services :

app/config/services.php
use Ubiquity\utils\http\session\PhpSession;
use Ubiquity\controllers\Startup;
use app\session\MyCsrfProtection;

Startup::setSessionInstance(new PhpSession(new MyCsrfProtection()));

Désactiver la protection

Si vous n’avez pas besoin de protéger votre session contre les attaques Csrf, démarrez la session avec la classe « NoCsrfProtection ».

app/config/services.php
use Ubiquity\utils\http\session\PhpSession;
use Ubiquity\controllers\Startup;
use Ubiquity\utils\http\session\protection\NoCsrfProtection;

Startup::setSessionInstance(new PhpSession(new NoCsrfProtection()));

Gestion CSRF

Le service CsrfManager peut être démarré directement depuis l’interface webtools. |Son rôle est de fournir des outils pour protéger les routes sensibles des attaques Csrf (celles qui permettent la validation des formulaires par exemple).

../_images/csrf-manager-started.png
  • Le service est démarré dans le fichier services.php.

app/config/services.php
 \Ubiquity\security\csrf\CsrfManager::start();

Exemple de protection de formulaire :

La vue du formulaire :

<form id="frm-bar" action='/submit' method='post'>
   {{ csrf('frm-bar') }}
   <input type='text' id='sensitiveData' name='sensitiveData'>
</form>

La méthode csrf génère un jeton pour le formulaire (En ajoutant un champ caché dans le formulaire correspondant au jeton.).

La soumission du formulaire dans un contrôleur :

use Ubiquity\security\csrf\UCsrfHttp;

#[Post('/submit')]
public function submit(){
   if(UCsrfHttp::isValidPost('frm-bar')){
      //Token is valid! => do something with post datas
   }
}

Note

Il est également possible de gérer cette protection via un cookie.

Exemple de protection avec ajax :

Le champ méta csrf-token est généré sur toutes les pages.

app/controllers/BaseController.php
abstract class ControllerBase extends Controller{
   protected $headerView = "@activeTheme/main/vHeader.html";
   protected $footerView = "@activeTheme/main/vFooter.html";

   public function initialize() {
      if (! URequest::isAjax ()) {
         $meta=UCsrfHttp::getTokenMeta('postAjax');
         $this->loadView ( $this->headerView,['meta'=>$meta] );
      }
   }
}

Ce champ est ajouté dans la headerView :

app/views/main/vHeader.html
{% block header %}
   <base href="{{config["siteUrl"]}}">
   <meta charset="UTF-8">
   <link rel="icon" href="data:;base64,iVBORw0KGgo=">
   {{meta | raw}}
   <title>Tests</title>
{% endblock %}

Exemple avec un bouton qui envoie des données via ajax. Le paramètre csrf est mis à true. Donc quand la requête est postée, le csrf-token est envoyé dans les headers de la requête.

#[Get(path: "/ajax")]
public function ajax(){
   $this->jquery->postOnClick('#bt','/postAjax','{id:55}','#myResponse',['csrf'=>true]);
   $this->jquery->renderDefaultView();
}

La route de soumission peut vérifier la présence et la validité du jeton :

#[Post(path: "postAjax")]
public function postAjax(){
   if(UCsrfHttp::isValidMeta('postAjax')){
      var_dump($_POST);
   }else{
      echo 'invalid or absent meta csrf-token';
   }
}

Gestionnaire de cryptage

Le service EncryptionManager peut être lancé directement à partir de l’interface webtools.

  • Dans ce cas, une clé est générée dans le fichier de configuration « app/config/config.php ».

  • Le service est démarré dans le fichier services.php.

app/config/services.php
 \Ubiquity\security\data\EncryptionManager::start($config);

Note

Par défaut, le cryptage est effectué en AES-128.

../_images/encryption-manager-started.png

Changement du cypher code :

Mise à niveau vers AES-256 :

app/config/services.php
\Ubiquity\security\data\EncryptionManager::startProd($config, Encryption::AES256);

Générer une nouvelle clé :

Ubiquity new:key 256

La nouvelle clé est générée dans le fichier app/config/config.php.

Cryptage des données des modèles

Le transformateur Crypt peut aussi être utilisé sur les membres d’un modèle :

app/models/User.php
 class Foo{
     #[Transformer(name: "crypt")]
     private $secret;
     ...
 }

Usage:

$o=new Foo();
$o->setSecret('bar');
TransformersManager::transformInstance($o);// secret member is encrypted

Cryptage des données génériques

Cryptage des chaînes :

$encryptedBar=EncryptionManager::encryptString('bar');

Pour ensuite le décrypter :

echo EncryptionManager::decryptString($encryptedBar);

Il est possible de crypter tout type de données :

$encryptedUser=EncryptionManager::encrypt($user);

Pour ensuite le décrypter, avec éventuellement sérialisation/désérialisation s’il s’agit d’un objet :

$user=EncryptionManager::decrypt($encryptedUser);

Gestionnaire des politiques de sécurité du contenu

Le service ContentSecurityManager peut être lancé directement à partir de l’interface webtools.

  • Le service est démarré dans le fichier services.php.

app/config/services.php
\Ubiquity\security\csp\ContentSecurityManager::start(reportOnly: true,onNonce: function($name,$value){
     if($name==='jsUtils') {
             \Ubiquity\security\csp\ContentSecurityManager::defaultUbiquityDebug()->addNonce($value, \Ubiquity\security\csp\CspDirectives::SCRIPT_SRC)->addHeaderToResponse();
     }
});

Note

Avec cette configuration par défaut, un nonce est ajouté aux scripts jquery générés avec phpmv-ui. Le contrôle du CSP se fait en mode Report-only .

../_images/csp-manager-started.png

Ajout d’un nonce

Exemple d’ajout de nonce sur les pages d’en-tête et de pied de page :

Mise à jour du contrôleur de base

app/controllers/ControllerBase.php
namespace controllers;

use Ubiquity\controllers\Controller;
use Ubiquity\security\csp\ContentSecurityManager;
use Ubiquity\utils\http\URequest;

/**
 * controllers$ControllerBase
 */
abstract class ControllerBase extends Controller {

     protected $headerView = "@activeTheme/main/vHeader.html";

     protected $footerView = "@activeTheme/main/vFooter.html";

     protected $nonce;

     public function initialize() {
             $this->nonce=ContentSecurityManager::getNonce('jsUtils');
             if (! URequest::isAjax()) {
                     $this->loadView($this->headerView,['nonce'=>$this->nonce]);
             }
     }

     public function finalize() {
             if (! URequest::isAjax()) {
                     $this->loadView($this->footerView,['nonce'=>$this->nonce]);
             }
     }
}

Gestion des mots de passe

Jeton d’utilisateurs