Guide pour créer des logiciels PHP sécurisés en 2018

Parce que tous les développeurs ne parlent pas anglais, voici une traduction (surement imparfaite) de l’article « The 2018 Guide to Building Secure PHP Software » publié sur le blog de ParagonIE par Scott Arciszewski‏.

Comme l’année 2018 vient de commencer, les experts en technologies — et plus précisément les développeurs web — doivent se débarrasser de leurs vieilles pratiques et croyances à propos du développement d’applications PHP. C’est particulièrement vrai pour toute personne qui croit encore que c’est un objectif impossible.

Ce guide sert de complément à l’e-book, PHP: The Right Way, en mettant l’accent sur la sécurité et pas sur les aspects généraux de la programmation PHP (par exemple les conventions d’écriture).

Sommaire

  1. Les version de PHP
  2. Gestion de dépendances avec Composer
  3. HTTPS et la sécurité du navigateur
  4. Déveloper des logiciels PHP sécurisés
  5. Cas d’usage spécifiques
  6. Un mot de l’auteur
  7. Ressources

Les versions de PHP

En résumé : Sauf si vous n’avez pas la main dessus, vous voulez utiliser PHP 7.2 courant 2018 et prévoyez de migrer à 7.3 début 2019.

PHP 7.2 a été publié le 30 novembre 2017.

À ce jour, seuls PHP 7.1 et 7.2 sont supportés activement par les développeurs du langage de programmation PHP, alors que PHP 5.6 et 7.0 ne recevrons plus que des patchs de sécurité pour encore environ un an.

Certains systèmes d’exploitations fournissent un support sur le long terme pour les versions non supportées de PHP, mais cette pratique est généralement considérée dangereuse. En particulier, leur mauvaise habitude d’appliquer les correctifs de sécurité sans incrémenter le numéro de version, qui ne permet pas d’avoir une vision claire à propos du niveau de sécurité d’un système uniquement à partir de la version de PHP.

Par conséquent, indépendamment des promesses faites par les différents fournisseurs, vous devez toujours vous efforcer d’utiliser uniquement les versions activement supportées de PHP. Ce faisant, même si vous finissez sur une version ne bénéficiant que des correctifs de sécurité pendant un moment, un effort constant de mise à jour vous évitera les mauvaises surprises.

Gestion des dépendances

En résumé : Utilisez Composer.

La solution de gestion de dépendances la plus aboutie dans l’écosystème PHP est Composer. PHP: The Right Way propose une section entière dédiée à commencer avec Composer que nous recommandons fortement.

Si vous n’utilisez pas Composer pour gérer vos dépendances, vous finirez par vous retrouver (souvent plus tôt que vous ne le croyez) dans une situation où l’une des bibliothèques logicielles dont vous dépendez devienne complètement obsolète et qu’un programme utilisant une faille dans ces vieilles versions commence à circuler parmi les criminels informatiques.

Important : N’oubliez pas de toujours garder vos dépendances à jour au fur et à mesure de vos développements. Heureusement, une seule ligne suffit :

composer update

Si vous faites quelque chose de particulièrement spécialisé qui nécessite l’utilisation d’extensions PHP (qui sont écrites en C), vous ne pourrez pas les installer avec Composer. Vous aurez aussi besoin de PECL.

Paquets recommandés

Peu importe ce que vous construisez, vous tirerez certainement un bénéfice de ces dépendances. C’est en plus de ce que recommandent la plupart des développeurs PHP (PHPUnit, PHP-CS-Fixer, etc.).

roave/security-advisories

Le paquet Roave’s security-advisories utilises le dépôt Friends of PHP pour assurer que votre projet ne dépend d’aucun paquet connu comme vulnérable.

composer require roave/security-advisories:dev-master

Sinon, vous pouvez uploader votre fichier composer.lock chez Sensio Labs dans le cadre d’un workflow de vérification des vulnérabilités automatisé pour vous alerter de tout paquet obsolète.

vimeo/psalm

Psalm est un outil d’analyse statique qui vous aide à identifier les bugs potentiels dans votre code. Bien qu’il existe d’autres bon outils d’analyse statique (comme Phan et PHPStan qui sont tout deux excellents), si vous avez besoin de supporter PHP 5, Pslam est l’outil d’analyse statique pour PHP 5.4+.

Utiliser Psalm est relativement simple :

# La version 1 n'existe pas encore, mais ce sera le cas un jour :
composer require --dev vimeo/psalm:^0

# Ne le faites qu'une seule fois :
vendor/bin/psalm --init

# Faites-le aussi souvent que nécessaire :
vendor/bin/psalm

Si vous le lancez sur une base de code existante pour la première fois, vous devriez voir beaucoup de rouge. À moins que vous construisiez une application aussi grande que WordPress, il est peu probable que l’effort requis pour que tous les tests passent soit considéré comme Herculéen.

Quel que soit l’outil d’analyse statique que vous choisissez, nous vous recommandons de l’utilisez dans votre workflow d’intégration continue (le cas échéant) afin qu’il soit exécuté à chaque modification du code.

HTTPS et la sécurité du navigateur

En résumé : HTTPS, quoi tester et les en-têtes liés à la sécurité

En 2018, il n’est plus acceptable pour des sites web d’être accessible par HTTP non sécurisé. Heureusement, il est possible d’obtenir gratuitement des certificats TLS et de les renouveler automatiquement grâce au protocole ACME et à l’autorité de certification Let’s Encrypt.

Intégrer ACME à votre serveur web est un jeu d’enfant.

Vous pensez peut-être : « Ok, j’ai un certificat TLS, maintenant je dois passer des heures à tripoter la configuration avant qu’elle ne soit sécurisée et rapide ».

Nan! Mozilla est de retour. Vous pouvez utiliser le générateur de configuration pour créer les suites de chiffrement recommandées en fonction de votre public cible.

HTTPS (HTTP sur TLS) est absolument non négociable si vous voulez que votre site web soit sécurisé. L’utilisation d’HTTPS élimine instantanément plusieurs types d’attaques sur vos utilisateurs (injection de contenu man-in-the-middle, écoute réseau et plusieurs formes de manipulations de sessions qui peuvent permettre l’usurpation d’identité).

Les en-têtes liés à la sécurité

Cependant, bien que l’utilisation du protocole HTTPS sur votre serveur offre de nombreux avantages en matière de sécurité et de performances pour vos utilisateurs, vous pouvez aller plus loin en utilisant d’autres fonctions de sécurité du navigateur. La plupart d’entre elles impliquent l’envoi d’un en-tête de réponse HTTP avec votre contenu.

  • Content-Security-Policy
    • Vous avez besoin de cet en-tête parce qu’il vous donne le contrôle sur les ressources internes et externes pouvant être chargées par le navigateur, ce qui fournit une puissante couche de défense contre les vulnérabilités de script inter-sites (XSS).
    • Voir CSP-Builder pour un moyen rapide et facile de déployer / gérer les stratégies de sécurité du contenu.
    • Pour une analyse plus en profondeur, cette introduction aux en-têtes Content-Security-Policy par Scott Helme est un bon point de départ.
  • Expect-CT
    • Vous avez besoin de cet en-tête parce qu’il ajoute une couche de protection contre les autorités de certification malveillantes / compromises en forçant les mauvais acteurs à publier les preuves de leurs certificats erronés dans une structure de données vérifiable publiquement. Apprenez en plus à propos d’Expect-CT.
    • Définissez le à enforce,max-age=30 dans un premier temps, et augmentez la valeur max-age au fur et à mesure que vous gagnez en confiance dans le fait que cet en-tête n’entrainera pas de perturbation du service.
  • Referrer-Policy
  • Strict-Transport-Security
    • Vous avez besoin de cet en-tête parce qu’il dit au navigateur de forcer toutes les futures requêtes vers la même origine sur HTTPS plutôt que HTTP non sécurisé.
    • Définissez le à max-age=30 lors de votre premier déploiement, ensuite augmentez la valeur à une valeur élevée (par exemple 31536000) quand vous êtes sûr que rien ne va casser.
  • X-Content-Type-Options
    • Vous avez besoin de cet en-tête parce que la confusion de type MIME peut conduire à des résultats imprévisibles, incluant des cas bizarres qui introduisent des vulnérabilités XSS. Cet en-tête doit être accompagné d’un en-tête Content-Type standard.
    • Définissez le à nosniff sauf si vous avez besoin du comportement par défaut (par exemple pour un téléchargement de fichier).
  • X-Frame-Options
    • Vous avez besoin de cet en-tête parce qu’il vous permet déviter le clickjacking.
    • Définissez le à DENY (ou SAMEORIGIN, mais seulement si vous utilisez des éléments <frame>).
  • X-XSS-Protection
    • Vous avez besoin de cet en-tête parce qu’il active quelques fonctionnalités navigteur anti-XSS qui ne sont pas activées par défaut.
    • Définissez le à 1; mode=block

Dans la même veine, si vous utilisez les fonctions de gestion de session intégrées à PHP (qui sont recommandées), vous voudrez probablement appeler session_start() comme ceci :

session_start([
    'cookie_httponly' => true,
    'cookie_secure' => true
]);

Cela force votre application à utiliser les signaux HTTP-Only et Secure lors de l’envoi du cookie d’identifiant de session, ce qui empêche de réussir une attaque XSS en dérobant les cookies de l’utilisateur et qui limite leur transmission aux connexions HTTPS. Nous avons déjà couvert les sessions PHP sécurisées (en) dans un article de blog de 2015.

Contrôle d’intégrité des sous-ressources

Vous travaillerez probablement un jour sur un projet qui utilise un CDN pour servir les frameworks JavaScript/CSS et librairies génériques depuis un endroit central.

Il n’est pas surprenant que les ingénieurs en sécurité aient déjà prévu le piège le plus évident : Si un grand nombre de sites internet utilisent un CDN pour servir une partie de leurs contenus, hacker le CDN et remplacer les contenus vous permettrais d’injecter le code de votre choix sur des dizaines de milliers (sinon des millions) de sites web.

Découvrez le contrôle d’intégrité des sous-ressources

Le contrôle d’intégrité des sous ressources (SRI) vous permet de définir un hash du contenu du fichier que vous attendez du CDN. SRI tel qu’il est actuellement implémenté, autorise uniquement l’utilisation de fonctions de hachage cryptographiques sécurisées, ce qui signifie qu’il est impossible de générer une version malveillante des ressources qui produisent le même hachage que le fichier d’origine.

Exemple concret : Bootstrap v4-alpha utilise SRI dans le code d’exemple d’intégration avec un CDN.

<link
    rel="stylesheet"
    href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"
    integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ"
    crossorigin="anonymous"
/> <script
    src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"
    integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn"
    crossorigin="anonymous"
></script>

Relations entre les documents

Les développeurs web définissent souvent l’attribut target sur les hyperliens (par exemple target="_blank" pour ouvrir dans une nouvelle fenêtre). Toutefois, si vous ne transmettez pas également la balise rel = "noopener", vous pouvez autoriser la page cible à prendre le contrôle de la page d’origine (en).

Ne faites pas ça !

<a href="http://example.com" target="_blank">Click here</a>

Ce code permet à example.com de prendre le contrôle de la page courante.

Faites ceci plutôt

<a href="http://example.com" target="_blank" rel="noopener noreferrer">Click here</a>

Le site example.com s’ouvre dans une nouvelle fenêtre, mais ne donne pas le contrôle sur la fenêtre actuelle à un tiers, qui est potentiellement malveillant.

Un peu de lecture pour aller plus loin (en).

Développer des logiciels PHP sécurisés

Si la sécurité des applications est un nouveau sujet pour vous, commencez par l’article : Une introduction simple à la sécurité des applications (en).

La plupart des professionnels de la sécurité orientent les développeurs vers des ressources telles que le Top 10 d’OWASP.

Cependant, la plupart des vulnérabilités courantes peuvent être exprimées comme des versions spécifiques du même problème de sécurité de haut niveau (code / données non correctement séparés, logique non conforme, environnement d’exploitation non sécurisé ou protocoles de cryptographie brisés).

Notre hypothèse est qu’enseigner à des néophytes de la sécurité une version simplifiée, plus fondamentale de ces problèmes de sécurité et comment les résoudre mènera à une meilleure ingénierie de la sécurité sur le long terme.

Interaction avec la base de données

En détail : Empêcher les injections SQL dans les applications PHP (en)

Si vous écrivez des requêtes SQL vous-même, assurez-vous d’utiliser des instructions préparées et que toutes les informations fournies par le réseau ou le système de fichier sont passés en paramètre plutôt que d’être concaténé dans la requête.
En outre, assurez-vous que vous n’utilisez pas des instructions préparées émulées.

Pour de meilleurs résultats, utilisez EasyDB.

Ne faites pas ça :

/* Insecure code: */ 
$query = $pdo->query("SELECT * FROM users WHERE username = '" . $_GET['username'] . "'");

Mais plutôt :

/* Secure against SQL injection: */
$results = $easydb->row("SELECT * FROM users WHERE username = ?", $_GET['username']);

Il existe d’autres couches d’abstraction de base de données qui offrent une sécurité équivalente (EasyDB utilise en réalité les objets PDO en interne, mais fait tout son possible pour désactiver l’émulation d’instructions préparées en faveur d’instructions préparées réelles pour éviter les problèmes de sécurité). Tant que l’entrée de l’utilisateur ne peut pas influencer la structure des requêtes, vous êtes en sécurité (Cela inclut les procédures stockées).

Upload de fichiers

En détail : Comment autoriser les utilisateurs à uploader des fichiers en toute sécurité (en)

Accepter l’upload de fichier est quelque chose de risqué, mais c’est possible de le faire en toute sécurité, à condition de prendre quelques précautions élémentaires. A savoir : Empêcher l’accès direct aux fichiers uploadés d’une manière qui pourrait accidentellement leur permettre d’être exécuté ou interprété.

Les fichiers uploadés doivent être en lecture seule ou lecture/écriture, mais jamais exécutable.

Si la racine de votre site web est /var/www/example.com, vous ne devez pas stocker vos fichier dans /var/www/example.com/uploaded_files.

Au lieu de cela, les fichiers doivent être stockés dans un répertoire séparé qui n’est pas directement accessible (par exemple /var/www/example.com-uploaded/), de peur qu’ils ne soient accidentellement exécutés comme un script côté serveur et ouvrent la porte à l’exécution de code distant.

Une solution plus propre consiste à déplacer la racine du site d’un niveau vers le bas (c’est-à-dire vers /var/www/example.com/public).

L’autre problème avec les téléchargements de fichiers est, et bien, de pouvoir les télécharger en toute sécurité.

  • Les images SVG, lorsqu’elles sont accédées directement, exécuterons du code JavaScript dans le navigateur de l’utilisateur. C’est vrai malgré le préfixe image/ dans le type MIME.
  • Le sniff de type MIME peut conduire à des attaques de type, comme discuté précédemment. Voir X-Content-Type-Options.
  • Si vous ne prenez pas en compte ces conseils sur la façon de stocker les fichiers téléchargés en toute sécurité, un attaquant qui parvient à uploader un fichier .php or .phtml pourra exécuter un code arbitraire en accédant directement au fichier depuis son navigateur, ce qui lui donnera un contrôle total sur le serveur. Faites attention.

Scripts inter-sites (XSS)

En détail : Tout ce que vous devez savoir sur la prévention des vulnérabilités de script inter-sites en PHP (en)

Dans un monde parfait, XSS serait aussi facile à éviter que l’injection SQL. Nous aurions une API simple et facile à utiliser pour séparer la structure d’un document des données qu’il contient.

Malheureusement, le quotidien de la plupart des développeurs web consiste à générer un long blob de HTML et à l’envoyer dans une réponse HTTP. Ce n’est pas exclusif à PHP, c’est simplement la façon de faire du développement web.

La réduction des vulnérabilités XSS n’est pas une cause perdue. Cependant, tout dans la section sur la sécurité du navigateur devient soudainement très pertinent. En bref :

  1. Toujours échapper en sortie, jamais en entrée. Si vous stockez des données assainies dans une base de données, et qu’une vulnérabilité d’injection SQL est détectée ailleurs, l’attaquant peut complètement contourner votre protection XSS en polluant l’enregistrement fiable prêt à être affiché avec du code malveillant.
  2. Si votre framework dispose d’un moteur de template proposant un filtrage contextuel automatique, utilisez-le. C’est ensuite le travail de votre framework de le faire en toute sécurité.
  3. echo htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8'); est un moyen sûr et efficace d’arrêter toutes les attaques XSS sur une page Web encodée en UTF-8, mais n’autorise aucun code HTML..
  4. Si vous avez la possibilité d’utiliser Markdown au lieu de HTML, n’utilisez pas HTML.
  5. Si vous devez autoriser du HTML et n’utilisez pas de moteur de template (voir n°1), utilisez HTML Purifier. HTML Purifier n’est pas adapté pour l’échappement d’attributs HTML.

Falsification de requêtes inter-sites (CSRF)

L’objet de cette attaque est de transmettre à un utilisateur authentifié une requête HTTP falsifiée qui pointe sur une action interne au site, afin qu’il l’exécute sans en avoir conscience et en utilisant ses propres droits. L’utilisateur devient donc complice d’une attaque sans même s’en rendre compte. L’attaque étant actionnée par l’utilisateur, un grand nombre de systèmes d’authentification sont contournés.

Cela peut généralement être facilement résolu en deux étapes simples :

  1. Utilisez HTTPS, c’est un pré-requis. Sans HTTPS, toute défense que vous pourriez espérer monter devient fragile. Cependant, HTTPS seul n’empêche pas CSRF.
  2. Ajouter une authentification de type Challenge-Response (en).
    • Ajoutez un champ caché dans tous les formulaires ;
    • Remplissez-le avec une valeur aléatoire sécurisée cryptographiquement (appelée un jeton) ;
    • Lors de la soumission, vérifiez que le champ de formulaire est bien transmis et qu’il contient la valeur attendue.

Nous avons écrit une librairie appelée Anti-CSRF qui va un peu plus loin :

  • Vous pouvez rendre chaque jeton utilisable une seule fois et ainsi éviter de rejouer plusieurs fois la même requête.
    • Les jetons sont stockés dans le back-office.
    • Une rotation des jetons est effectuée quand le nombre maximum a été atteint, les plus vieux en premier.
  • Chaque jeton peut être lié à une URL spécifique.
    • Si un jeton est intercepté, il ne peut pas être utilisé dans un autre contexte.
  • Si besoin, les jetons peuvent être attachés à une adresse IP spécifique.
  • Depuis la version v2.1, les jetons peuvent être réutilisés (par exemple pour les requêtes AJAX).

Si vous n’utilisez pas un framework qui gère la protection CSRF pour vous, jetez un oeil à Anti-CSRF.

Dans un future proche, les cookies SameSite nous permettront d’arrêter les attaques CSRF (en) beaucoup plus simplement.

Attaques XML (XXE, Injections XPath)

Il y a deux vulnérabilités majeures qui pointent leurs vilaines têtes dans les applications qui font beaucoup de traitement XML :

  1. Les entités XML externes (XXE)
  2. Les injections XPath

Les attaques XXE peuvent être utilisées comme point de départ pour l’inclusion de fichier locaux / distants malveillants, entre autres choses.

Une des versions antérieures de Google Docs est connue pour avoir succombée à XXE, mais elle est en grande partie inconnue en dehors des applications métier qui font beaucoup de travail XML lourd.

La principale barrière contre les attaques XXE est la suivante :

libxml_disable_entity_loader(true);

Les injections XPath sont très proches des injections SQL, sauf qu’elles s’appliquent aux documents XML.

Heureusement, les situations dans lesquelles un utilisateur est amené à saisir une requête XPath sont vraiment rares dans l’écosystème PHP.

Malheureusement, cela signifie également que la meilleure protection disponible (requêtes XPath précompilées et paramétrées) n’est pas présente dans l’écosystème PHP.

Le mieux est d’utiliser une liste blanche de caractères autorisés sur toutes les données qui touchent la requête XPath.

<?php declare(strict_types=1);

class SafeXPathEscaper
{
    /**
     * @param string $input
     * @return string
     */
    public static function allowAlphaNumeric(string $input): string
    {
        return \preg_replace('#[^A-Za-z0-9]#', '', $input);
    }
    
    /**
     * @param string $input
     * @return string
     */
    public static function allowNumeric(string $input): string
    {
        return \preg_replace('#[^0-9]#', '', $input);
    }
}

// Usage:
$selected = $xml->xpath(
    "/user/username/" . SafeXPathEscaper::allowAlphaNumeric(
        $_GET['username']
    )
);

Les listes blanches sont plus sûres que les listes noires.

Désérialisation et injection d’objets PHP

En détail : Implémentation sécurisée de (dé)sérialization en PHP (en)

Si vous transmettez des données non fiables à unserialize(), vous vous attendez généralement l’un des deux résultats suivants :

  1. Injection d’objets PHP, qui peut être utilisé pour lancer une chaîne POP et déclencher d’autres vulnérabilités à partir d’objets mal utilisés ;
  2. Corruption mémoire dans l’interpréteur PHP lui-même.

La plupart des développeurs préfèrent utiliser la sérialisation JSON à la place, c’est une nette amélioration dans la sécurité de leur logiciel, mais gardez à l’esprit que json_decode() est vulnérable aux attaques par collision de hachage (Hash-DoS). Malheureusement, le correctif aux problèmes de Hash-DOS dans PHP n’a pas encore été apporté.

La migration de djb33 vers SipHash, avec le plus haut bit de la sortie de hachage mis à 1 pour l’entrée de chaîne et à 0 pour les entrées entières, avec une clé par requête fournie par un CSPRNG, résoudrait totalement ces attaques.

Malheureusement, l’équipe PHP n’est pas encore prête à lâcher les gains de performance qu’ils ont accumulés avec PHP 7.x. Il est difficile de les convaincre de laisser tomber djb33 (qui est très rapide, mais pas sécurisé) en faveur de SipHash (qui est rapide, pas autant que djb33, mais beaucoup plus sécurisé). Un impact significatif sur les performances pourrait même décourager l’adoption de futures versions, ce qui serait mauvais pour la sécurité.

La meilleure chose à faire est donc :

  • Utiliser JSON, parce que c’est plus sur que unserialize().
  • Lorsque vous le pouvez, assurez-vous que les entrées sont authentifiées avant de les désérialiser.
    • Pour les données que vous fournissez à l’utilisateur final, utilisez sodium_crypto_auth() et sodium_crypto_auth_verify() avec une clé secrète connue uniquement du serveur web.
    • Pour les données fournies par d’autres tiers, faites en sorte qu’ils signent leurs messages JSON avec sodium_crypto_sign(), puis vérifiez-les avec sodium_crypto_sign_open() et la clé publique du tiers.
  • Lorsque vous ne pouvez pas authentifier les chaînes JSON, imposez une limitation d’usage stricte et bloquez les adresses IP pour réduire le nombre de récidivistes.

Hachage des mots de passe

En détail : Comment stocker, en 2016, vos mots de passe utilisateurs en toute sécurité (en)

Le stockage sécurisé des mots de passe a été un sujet de débats passionés, mais aujourd’hui c’est relativement simple à mettre en place, surtout en PHP :

$hash = \password_hash($password, PASSWORD_DEFAULT);

if (\password_verify($password, $hash)) {
    // Authenticated.
    if (\password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        // Rehash, update database.
    }
}

Vous n’avez même pas besoin de savoir quel algorithme est utilisé derrière, car si vous utilisez la dernière version de PHP, vous utiliserez également l’état de l’art actuel et les mots de passe des utilisateurs seront automatiquement mis à jour dès qu’un nouvel algorithme par défaut est disponible (grâce à password_needs_rehash()).

Quoi que vous fassiez, ne faites pas comme WordPress (en).

Si vous êtes curieux, cependant : de PHP 5.5 à 7.2, l’algorithme par défaut est bcrypt. À l’avenir, il pourrait passer à Argon2, le gagnant du concours d’hachage de mot de passe.

Si vous n’utilisiez pas l’API password_* et que vous avez des hash légacy qui ont besoin d’être migrés, assurez-vous de le faire de cette façon (en). Beaucoup d’entreprises l’ont mal fait ; la plus connue, Yahoo. Plus récemment, une mauvaise implémentation de la mise à niveau de mots de passe aurait causé le bug iamroot d’Apple.

Cryptographie à usage général

C’est un sujet sur lequel nous avons déjà beaucoup écrit :

Généralement, vous devriez toujours utiliser la bibliothèque Sodium (libsodium) pour la cryptographie de votre couche applicative. Si vous avez besoin de supporter des versions de PHP antérieure à 7.2 (jusqu’à 5.2.4) vous pouvez utiliser sodium_compat et prétendre que vos utilisateurs sont déjà sur 7.2.

Dans certains cas spécifiques, vous pouvez avoir besoin d’une bibliothèque différente en raison des choix d’algorithmes ou d’interopérabilité.
En cas de doute, consultez un expert en cryptographie sur les choix de chiffrement et un ingénieur en cryptographie pour savoir si l’implémentation est sécurisée ou non. (C’est un des services que nous fournissons.)

Aléatoire

En détail : Comment générer en toute sécurité des chaînes et entiers aléatoires en PHP (en)

Si vous avez besoin de nombre aléatoires, utilisez random_int(). Si vous avez besoin de chaînes d’octets aléatoires, utilisez random_bytes(). N’utilisez pas mt_rand(), rand(), ou uniqid() pour cela.

Si vous avez besoin de générer des nombres pseudo-aléatoires à partir d’un seed, au lieu de srand() ou mt_srand(), regardez plutôt SeedSpring.

<?php use ParagonIE\SeedSpring\SeedSpring;
$seed = random_bytes(16);
$rng = new SeedSpring($seed);
$data = $rng->getBytes(1024); $int = $rng->getInt(1, 100);

Requêtes HTTPS côté serveur

En bref : Assurez vous que la validation des certificats TLS n’est pas désactivé.

N’hésitez pas à utiliser un client HTTP compatible PSR-7 avec lequel vous êtes déjà familier. Nous aimons Guzzle. Certaines personnes aiment travailler directement avec cURL.

N’hésitez pas à vous pencher sur une couche d’abstraction générique comme HTTPlug pour plus d’interopérabilité.

Quoi que vous choisissiez, assurez-vous d’utiliser Certainty pour garantir que vous disposez toujours du paquet CACert le plus récent (en), ce qui vous permet d’activer les paramètres de validation des certificats TLS les plus stricts et de sécuriser les requêtes HTTPS sortantes.

Installer Certainty est relativement simple :

composer require paragonie/certainty:^1

Et l’utiliser aussi :

<?php use ParagonIE\Certainty\RemoteFetch;

$latestCACertBundle = (new RemoteFetch())->getLatestBundle();

# cURL users:
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_CAINFO, $latestCACertBundle->getFilePath());

# Guzzle users:
    /** @var \GuzzleHttp\Client $http */
    $repsonse = $http->get(
        'https://example.com', 
        [
            'verify' => $latestCACertBundle->getFilePath()
        ]
    );

Cela vous protègera des attaques man-in-the-middle entre votre serveur Web et les APIs tierces avec lesquelles vous communiquez.

Avons-nous vraiment besoin de Certainty ?

Certainty n’est pas à proprement parlé nécessaire pour protéger votre système. Son absence n’est pas signe de vulnérabilité.

Mais, sans cette libraire, le logiciel doit deviner où se trouve le paquet CACert du système d’exploitation. Il échoue souvent ce qui provoque des problèmes.

Historiquement, cela a incité de nombreux développeurs à simplement désactiver la validation des certificats afin que leur code « fonctionne » sans se rendre compte à quel point ils étaient vulnérables aux attaques actives.

Certainty fournis les paquets CACert à jour et dans un endroit prévisible. Il fournit également beaucoup d’outils pour les entreprises qui souhaitent gérer leur propre CA interne .

Qui désactive la validation des certificats ?

Les développeurs de plugins / extensions pour les systèmes de gestion de contenu populaires (WordPress, Magento, etc.) le font ! C’est un énorme problème que nous essayons de résoudre au niveau de l’écosystème. Ce n’est pas spécifique à un CMS donné, vous trouverez des plugins / etc. pour tout ces outils qui ne sont pas sécurisés de cette façon.

Si vous utilisez un tel CMS, cherchez dans vos plugins CURLOPT_SSL_VERIFYPEER et CURLOPT_SSL_VERIFYHOST et vous en trouverez surement qui définissent ces valeurs à FALSE.

Cas d’usage spécifiques

Maintenant que vous maîtrisez les bases pour construction des applications PHP sécurisées, examinons quelques cas d’utilisation plus spécialisés.

Cryptage interrogeable

En détail : Construire des bases de données cryptées interrogeables avec PHP et SQL (en)

Il serait intéressant d’utiliser des bases de données cryptées interrogeables, mais elles sont largement considérées comme non triviales à mettre en œuvre. L’article de blog ci-dessus tente de guider le lecteur à travers le développement de notre solution de manière incrémentale, mais essentiellement :

  1. Concevez votre architecture de sorte qu’une base de données compromise ne donne pas accès aux attaquants à vos clés de cryptographie ;
  2. Chiffrez les données sous une clé secrète ;
  3. Créez plusieurs index (avec leurs propres clés secrètes distinctes), basés sur HMAC ou un KDF sécurisé avec un salt statique (par exemple Argon2) ;
  4. Facultatif : tronquez la sortie de l’étape 3, utilisez-le comme filtre Bloom ;
  5. Utilisez la sortie de l’étape 3 ou 4 dans vos requêtes SELECT ;
  6. Décryptez les résultats.

À n’importe quelle étape du processus, vous pouvez faire des compromis en fonction de ce qui est logique pour votre cas d’utilisation.

Authentification par jeton sans Side-Channels

En détail : Jetons séparés : Protocole d’authentification basé sur des jetons sans Side-Channels (en)

En parlant des bases de données (section précédente), saviez-vous que les requêtes SELECT peuvent théoriquement être une source de fuites d’informations sur le temps d’exécution ?

Solution simple :

  1. Coupez vos jetons d’authentification en deux ;
  2. Utilisez une moitié dans vos requête SELECT ;
  3. Validez la seconde moitié en temps constant.
    • Vous pouvez aussi stocker un hash de la seconde moité au lieu du demi-jeton directement. Cela a du sens pour les jetons qui ne seront utilisés qu’une seule fois (par exemple les jetons de réinitialisation de mot de passe ou « se souvenir de moi sur cet ordinateur »).

Même si vous pouvez utiliser les fuites de temps d’exécution pour voler la moitié du jeton, le reste nécessitera une attaque en force brute pour réussir.

Développer des APIs sécurisées

En détail : Renforcez vos APIs développées en PHP avec Sapient (en)

Nous avons écrit SAPIENT, le Secure API ENgineering Toolkit (Boîte à outils d’ingénierie API sécurisée), pour faire de la communication authentifiée de serveur à serveur une évidence.

Sapient vous permet de crypter et / ou d’authentifier les messages, en utilisant la cryptographie à clé partagée ou à clé publique, en plus de la sécurité fournie par HTTPS.

Cela vous permet d’authentifier les requêtes et les réponses d’API à l’aide d’Ed25519 ou de crypter des messages sur un serveur cible qui ne peut être décrypté que par la clé secrète du serveur destinataire, même si un attaquant man-in-the-middle est présent et armé d’une Autorité de certification compromise.

Étant donné que chaque corps de message HTTP est authentifié par une cryptographie sécurisée, il peut être utilisé en toute sécurité à la place des protocoles de manipulation de jeton d’état (par exemple, OAuth). Cependant, quand il s’agit de cryptographie, il faut toujours être sûr que leur mise en œuvre est étudiée par des experts avant de faire quoi que ce soit de non standard.

Toute la cryptographie utilisée par Sapient est fournie par la bibliothèque de cryptographie Sodium.

Lectures complémentaires :

Paragon Initiative Enterprises utilise déjà Sapient dans de nombreux produits (y compris de nombreux projets de logiciels libres) et continuera d’ajouter des projets logiciels au portefeuille des utilisateurs de Sapient.

Journalisation des événements de sécurité avec Chronicle

En détail : Chronicle va vous aider à vous poser des questions sur le besoin de la technologie Blockchain (en)

Chronicle est un registre cryptographique fonctionnant en « append-only » et basé sur une structure de données en chaîne de hachage.
Sans exagérer, il a de nombreuses caractéristiques qui attirent aujourd’hui les entreprises vers les technologies de « blockchain ».

Mis à part les usages les plus créatifs d’un registre cryptographique « append-only », Chronicle est particulièrement intéressant lorsqu’il est intégré dans un SIEM, car vous pouvez envoyer des événements critiques de sécurité à une instance privée et ils deviennent immutables.

Si Chronicle est configuré pour faire une signature croisée de son hachage de base sur d’autres instances, et / ou s’il existe d’autres instances configurées pour répliquer le contenu de votre Chronicle, il devient extrêmement difficile pour les pirates d’altérer vos journaux d’événements de sécurité.

Avec Chronicle, vous obtenez toute la résilience que les blockchains promettent, sans aucun problème de confidentialité, de performances ou d’évolutivité.

Pour publier des données sur un Chronicle local, vous pouvez utiliser n’importe quelle API compatible Sapient, mais la solution la plus simple s’appelle Quill.

Un mot de l’auteur

Un lecteur astucieux aura remarqué que nous faisons beaucoup référence à notre propre travail (des articles de blog et des logiciels open source), mais nous ne faisons pas seulement référence à notre propre travail.

Ce n’était pas accidentel.

Notre société écrit des bibliothèques de sécurité et participe aux efforts d’amélioration de la sécurité de l’écosystème PHP depuis sa création début 2015.

Nous avons parcouru beaucoup de chemin, et notre ingénieur en sécurité (dont les récents ajouts pour une cryptographie plus sécurisée dans le noyau PHP viennent d’être intégrés dans PHP 7.2) est, de l’aveu général, pas très bon pour faire du bruit ou générer de l’intérêt autour de son travail. Il est très probable que vous n’ayez jamais entendu parler de la moitié des outils ou des bibliothèques que nous avons développés au fil du temps. Désolé pour ça.

Cependant, nous ne pouvons pas non plus être les précurseurs dans tous les domaines, donc, dans la mesure du possible, nous avons choisi de faire des liens vers le travail d’experts de l’industrie qui, selon nous, sont davantage liés au bien public qu’au petit égoïsme. C’est pourquoi une grande partie de la section dédiée à la sécurité dans le navigateur fait référence au travail de Scott Helme et son entreprise, qui ont fait un excellent travail en rendant ces nouvelles fonctionnalités de sécurité accessibles et compréhensibles pour les développeurs.

Ce guide n’est certainement pas exhaustif. Il y a presque autant de façons d’écrire du code non sécurisé que d’écrire du code en premier lieu. La sécurité est un état d’esprit plus qu’une destination. Avec tout ce qui est écrit ci-dessus, et les ressources qui suivent, nous espérons que les développeurs du monde entier auront de quoi écrire des logiciels sécurisés en PHP à partir de maintenant.

Ressources

Si vous avez tout suivi et que vous en voulez plus, vous pouvez être intéressé par notre liste de lecture autour de l’apprentissage de la sécurité des applications (en).

Si vous pensez que vous avez écrit un code suffisamment sécurisé et que vous voulez que nous le critiquions du point de vue d’un ingénieur de sécurité, c’est un service que nous fournissons à nos clients.

Si vous travaillez pour une entreprise qui doit subir des tests de conformité (PCI-DSS, ISO 27001, etc.), vous pouvez également engager notre société pour auditer votre code source. Notre processus est beaucoup plus convivial pour les développeurs que les autres sociétés de conseil en sécurité.

Ce qui suit est une liste de ressources fournies par les communautés PHP et de sécurité de l’information qui contribuent à sécuriser Internet à leur manière.

  • PHP: The Right Way, le guide de facto du développement PHP moderne, en ligne gratuitement.
  • Le générateur de configuration SSL de Mozilla
  • Let’s Encrypt, qui est l’autorité de certification faisant le plus pour créer un Internet plus sécurisé en fournissant gratuitement des certificats TLS.
  • Qualys SSL Labs fournit une suite de tests rapide et simple pour la configuration TLS. Pratiquement tout le monde l’utilise pour résoudre les problèmes de vérification et de certificats, car il fait très bien son travail.
  • Security Headers vous permet de vérifier si votre site web fonctionne correctement au niveau de l’utilisation des fonctionnalités de sécurité du navigateur pour protéger vos utilisateurs.
  • Report-URI est une excellente ressource gratuite pour démarrer rapidement l’implémentation des en-têtes de sécurité. Ils vous donnent une URI, que vous pouvez passer aux navigateurs de vos utilisateurs, et ils transmettrons les erreurs à cette URI si quelque chose casse ou si quelqu’un trouve un vecteur d’attaque XSS. Report-URI regroupe ces erreurs et vous permet de mieux corriger et trier ces rapports.
  • Le calendrier de l’avent pour la sécurité PHP par l’équipe derrière RIPSTech.
  • Snuffleupagus, un module PHP orienté sécurité (et le successeur spirituel de Suhosin, qui semble être largement abandonné).
  • PHP Delusions, un site dédié à mieux utiliser PHP. Le ton utilisé est très opiniâtre, mais l’auteur s’attache à être très clair et à apporter une grande précision technique, en particulier pour ceux qui ne connaissent pas bien les fonctionnalités de PDO.
  • Have I Been Pwned? aide les utilisateur à découvrir sur leurs données ont fait partie de fuites de données.

Publié par

Stéphane

Passionné par les nouvelles technologies, la veille est mon quotidien. Je mets au service mon expertise et ma curiosité pour la conceptions de solutions techniques pérennes. Consultant et formateur je manipule au quotidien PHP, SolR, ElasticSearch, JavaScript, HTML5, WordPress...

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *