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 :
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.
Cette protection peut être personnalisée en créant une classe implémentant VerifySessionCsrfInterface
.
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 :
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 ».
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).
Le service est démarré dans le fichier
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.
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 :
{% 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
.
\Ubiquity\security\data\EncryptionManager::start($config);
Note
Par défaut, le cryptage est effectué en AES-128
.
Changement du cypher code :
Mise à niveau vers AES-256 :
\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 :
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
.
\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 .
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
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]);
}
}
}