owasp zap openid connect kong oauth dast Cybersécurité

Tests dynamiques de sécurité (DAST) sous OWASP Zap avec…

L’ensemble du code source est disponible sur mon Github  😁

 

Un peu de théorie… 📚

On utilise de nos jours beaucoup de données, au seins de diverses applications, qui elles-mêmes peuvent s’échanger des données sur de multiples plateformes, accessible depuis une multitude d’appareils.

Quid de la sécurité pour éviter toute utilisation abusive ou frauduleuse ?

 

Protocole

OAuth

C’est un protocole permettant une autorisation à ‘consommer’ une API sécurisée. On peut alors interagir avec une application via une autorisation accordé par ce protocole sans avoir à partager son username ou mot de passe en clair.

 

OpenID Connect

C’est une surcouche à OAuth. Autant ce dernier et un protocole  d’autorisation de ressources, OIDC est un protocole d’identification, permettant de vérifier l’identité d’un utilisateur en se basant sur l’authentification fourni par un serveur d’autorisation.

 

Kong

Celui-ci est le serveur d’autorisation précédemment évoqué.

 

Logiciel

OWASP ZAP

Logiciel gratuit et open source, c’est l’outils de pentest le plus connue. Il n’as pas pour but de vous faire remonter la dernière faille zéro day du jour, mais plutôt de tester des mécanismes d’intrusions standard dont les plus connus.

Mais pourquoi un tuto? Car pour permettre de tester votre application dans sa globalité, et afin d’accéder à l’ensemble des pages et sous pages, vous allez devoir manipuler ZAP pour lui indiquer comment s’authentifier comme un vrai utilisateur. Vous ne parcourrez que partiellement votre appli web dans le cas contraire.

 

Authentification: form-based script

Vous allez avoir des scripts déjà fait au sein même de ZAP pour le cas d’application simple, tel que des sites wordpress. En effet, vous avez une URL statique, des credentials à envoyé dans une requête et ça fonctionne. Ce sont des form-based script.

 

Authentification: authentication-based script

Un autre type, appelé authentification-based script, peuvent ajouter des éléments pour des connexion à des sites plus complexe. Par exemple, si vous devez injecter en requête HTTP POST un token anti-CRSF. Il ajoute une sécurité en plus à votre site web, il est généré en général via des éléments renvoyé par le serveur (state, nonce, etc.). Cela permet d’éviter des attaques de type CRSF ( cross-site request forgery) qui consiste à transmettre à un user connecté une requête HTTP falsifié, résultant en une exécution d’une action sans être au courant ou l’initiateur, mais via ses propres droits. L’user est donc complice de l’attaque sans même sans rendre compte.

 

Authentification: HTTP-sender script

C’est celui-ci dont on va utiliser pour ce tuto. Ce script est appelé automatiquement lors de chaque requête que va envoyer ou recevoir ZAP vers votre application web. Mais pourquoi le script précédent ne peut-il pas correspondre ?

Voici un diagramme de séquence entre vos divers autorités :

diag de sequence zap open id connect kong oauth owasp2

 

Vous allez donc avoir une multitude d’échange (rendant impossible le login avec un script menant vers une page statique, au vu de nos multitude redirections on va manger un timeout), permettant de générer des variables aléatoires (state, nonce, crsf token, etc.). Avec celles-ci vous allez pouvoir vous loger dans votre application web, et enfin recevoir un cookie de session ou un JWT. C’est l’un des deux selon votre appli web, qui sera consommé par celle-ci afin de vérifier votre authenticité. Nous ne pouvons récupérer l’ensemble de ces champs avec l’un des type de script dont nous avons parlé précédent, et qui sont essentiel.

Le script HTTPSender interceptant chaque requête, on va pouvoir lui injecter en header HTTP GET ce cookie de session/JWT que l’on va stocker en variable globale, permettant de maintenir notre utilisateur connecté et permettant de parser l’appli web dans son intégralité.

 

Nous savons maintenant comment injecter ces tokens. Cependant, je n’ai parlé de comment le générer, avant de pouvoir l’envoyer des nos requêtes. Nous allons devoir utiliser une approche hybride selon la complexité de vos application web, avec d’une part du selenium/webdriver afin de remplir les champs comme bon nous semble, ne nous loger, et de récupérer les cookies et autre token que nous souhaitons. Vous pourrez toujours faire des appels supplémentaires GET ou POST si votre application nécessite d’avantage de complexité.

 

Si on doit résumer la procédure :

  1. Approche hybride selenium/webdriver pour bypass les xxx redirections vers la bonne page de login, avec l’ensemble des state/nonce généré aléatoirement qui sont nécéssaire
  2. Remplir la page de login avec nos credentials et valider
  3. Extraire le cookie de session ou JWT (bearer token) en variable globale
  4. Injecter ce cookie/JWT en header de requête pour tout HTTP GET via notre HTTPSender script afin d’être authentifié

 

Beaucoup de pratique 😁

Avant de vous lancer directement dans l’automatisation de vos tâches pour une CI/CD par exemple, dans un environnement sans UI, veillez à connaître dans les moindres détails l’ensemble des échanges qui s’effectue entre votre divers protocoles, car vous allez devoir scripter chaque requête à la main afin de reproduire une connexion à vos ressources comme si celle-ci était faîte depuis un navigateur. Cela va aller de la connexion sur le site avec vos credentials, avec la récupération de divers éléments (state, nonce, crsf token, etc.) afin de pouvoir en générer d’autres permettant de prouver votre identité ( divers cookie, token, etc.)

Afin de faciliter la tâche, je vous conseil de débuter de scripter la partie authentification à votre site web via l’application desktop dans un premier temps. Vous pourrez ainsi voir les divers échanges entre vos protocole, si vous ne connaissez pas la procédure dans sa globalité.

 

OWASP ZAP en mode desktop

Je vais détailler d’avantage le contenu des scripts dans la partie suivante, et me consacrer dans celle-ci principalement à vous présenter l’application desktop Zap.

 

Moteur de scripting

Zap est écrit en Java. Mais nous pouvons écrire nos scripts dans d’autres langages via des moteurs de scripts :

  • Javascript via Graal.js ou Oracle Nashorn
  • Zest via Mozilla
  • Python via Jython

J’aime bien le python, donc la suite du tuto sera utilisé avec Jython.

Python et javascript vous permettent d’écrire tout à la main vos scripts. Cependant, Zest vous permet d’enregistrer automatiquement toute action que vous faîtes sur votre appli web, lorsque vous la scanné en mode manuel. Vous pouvez ainsi vous décharger de la tâche pénible de scripter chaque action nécessaire pour être authentifier au sein de votre application, et juste naviguer en mode manuel via Zap sur votre application. Zest va s’occuper d’enregistrer chaque étape dans un format ressemblant à du JSON. Gain de temps assuré ! 😎

zest script
Enregistrement de la séquence d’authentification via le moteur de script Zest (Mozilla)
Scripting – Standalone script
create standalone script
Création d’un script autonome (standalone)
Scripting – HTTPSender script
create http sender script
Création d’un HTTPSender script
Test de l’authentification

Une fois que vos deux scripts sont crée on va pouvoir tester notre solution. Par exemple pour un scan actif.

Commencez par clique-droit sur votre script standalone, et exécutez le afin de reset le contenu de notre cookie. A faire entre chaque parcours manuel de votre application, sinon vous risquez de vous prendre un time out si votre cookie se refresh à chaque session.

Ensuite clique-droit sur votre script http-sender afin de l’activer.

Vous pouvez maintenant lancer votre scan actif et vérifier que le spider récupère bien des pages avec un code de retour OK (200). Choisissez votre point de départ et lancez le balayage :

 

On peut voir que le scan se passe comme souhaité. Vérifiez qu’il passe bien dans vos sous-domaines réservés aux utilisateurs authentifié.

OWASP ZAP en mode automatique/headless

Scripting – Standalone script

On commence par écrire notre premier script qui nous permet d’initialiser une seule et unique fois notre variable globale du cookie à null :

Scripting – HTTPSender script

La partie la plus importante du projet consiste à écrire notre script qui va à la fois nous permettre de nous connecter, de récupérer notre objet nous permettant de nous authentifier, pour enfin l’envoyer dans chaque requête qui passe par Zap.

On commence donc par divers imports de bibliothèque dont on va avoir besoin. Ne vous affolez pas à voir des imports de lib Java dans le script Python !

On y défini quelques variables globales, dont la page de connexion initiale à notre app web :

Lorsque vous créez un script HTTPSender avec le squelette de base, vous allez avoir ces deux fonctions de base :

  • sendingRequest : appelé à chaque envoie de requête à travers Zap vers notre app
  • ResponseReceived : appelé à chaque réponse de notre app vers Zap.

Nous n’utiliserons que la première, car nous souhaitons simplement modifier notre en-tête de requête afin d’ajouter un élément qui nous permette de prouver que l’on est un utilisateur authentifié.

La fonction est simple. On vérifie que notre cookie existe. Si c’est le cas, on l’injecte simplement à notre requête via une fonction défini plus tard. Dans le cas contraire, on va récupérer ce cookie d’abords.

Cette fonction est très généraliste, vous devrez l’adapter en fonction de l’ensemble des étapes nécessaires concernant votre type d’authentification. Chaque site étant différent, je ne peux vous la faire dans sa globalité. Mais le schéma global est le suivant :

  • Créer une fenêtre Firefox. Vous pouvez lui spécifier des arguments, par exemple –headless qui doit être obligatoire si vous tournez sous une CI/CD par exemple. Si vous êtes sur un environnement windows, vous devrez rajouter le –disable-gpu ( qui est une issue connue sur le github de Zap), ou encore ajouter –disable-extensions pour gagner en performance. Si vous avez un proxy d’entreprise par exemple, vous pourrez aussi lui passer.
  • Ouvrir Firefox sur votre page de login. Selon votre provider d’autorisation, vous allez avoir plusieurs redirections. J’ai rajouté une condition afin d’être certains d’être sur la bonne page de login à l’arrivée.
  • Remplir les champs pour s’authentifier via Selenium. Je vous ait mis quelques exemple pour trouver vos champs, et les remplir.
  • Une fois connecté et arrivé sur notre page final pour un utilisateur authentifié, je récupère mon cookie pour l’injecter dans ma variable global. Dans mon cas je récupère un cookie dont le nom est « session », ainsi que sa valeur.

On peut enfin dans une dernière fonction injecter notre cookie de session dans l’entête de l’ensemble de nos requêtes qui transitent par Zap, nous permettant de maintenir notre authentification durant tout le processus de scan :

 

Dans le cas ou vous souhaitez envoyer un Json Web Token (JWT ou appelé Bearer Token) c’est quasiment la même chose :

Dans ce cas là, n’oubliez pas de sauvegarder en variable globale dans la fonction login(), votre token d’accès ainsi que votre token d’expiration. Dans le cas que votre token ne dure pas une session complète mais pour un temps limité, vous devrez ajouter dans la méthode login() une étape permettant de vérifier que votre jeton est encore valide. Dans le cas contraire, il faudra repasser par l’étape login() afin de demander de renouveler votre jeton.

C’est fait de tête rapidos, mais le principe est là si vous souhaitez implémenter une vérification de token concernant sa date de validité et d’expiration :

 

Lancement en CI/CD

On lance notre image depuis le répo officiel :

Afin d’utiliser nos scripts, on doit les déplacer au sein même de notre image dans les dossiers correspondant : /scripts pour les scripts, et /plugin pour y mettre n’extension du moteur de script Jython. En effet il n’est pas disponible de base, il faut soit le rajouter à la main comme ceci, soit l’ajouter (indiqué dans la commande suivante) au lancement de Zap :

Nous n’avons plus qu’a lancer le script zap-x.sh (très important le -x afin de tourner dans un mode headless). J’autorise tout les IP à accéder à Zap en désactivant la clée API et en whitelistant via le name et regex. Vous pouvez ajouter des extensions ici à la volée, ou même mettre à jour ceux déjà présent :

 

Script global

Je fais référence à un script main.py dans ma dernière commande docker. En effet pas besoin dans ZAPDesktop, mais en version full-script, vous allez devoir avoir besoin d’un script que l’on peu qualifier de global, qui va discuter avec notre image de Zap lancé en mode daemon. Ce mode daemon va permettre à ZAP d’être à l’écoute de tout appel. Nous pourrons communiquer entre celui-ci et notre script main.py via l’api REST offerte.

Faîte vous un environnement virtuel Python, que ça soit Venv sur MAC OS ou Anaconda pour windows. On aura besoin de descendre une dépendance :

pip install python-owasp-zap-v2.4

 

Voici la manœuvre à suivre pour communiquer avec ZAP, et surtout comment charger, activer et lancer vos scripts afin de gérer toute l’étape d’authentification dans un environnement headless avant de lancer les spider pour crawl et de lancer les attaques via scanner :

 

Requête générique

Si votre flux d’authentification est plus complexe, et que vous devez récupérer des champs comme le State, None, ou encore un CRSF Token, je vous met ci dessous de quoi réaliser des requêtes génériques GET et POST dans le scritpt HTTPSender :

 

Cours logiciel - Electron

Chap 0 : Présentation de Electron

Présentation

Electron est un framework permettant de développer des applications bureaux multi plateforme ( Linux, Windows, MacOS ) avec des technologies web ( HTML, CSS et Typescript/Javascript ). Il est open source et permet de réaliser très rapidement des applications. Vous pensez que cela n’est pas possible ? Et pourtant vous en utilisez surement sans même le savoir ; Atom, Visual studio, Slack pour n’en citer que les plus gros.

Vous allez donc développer votre application comme si vous développiez un site web.

 

Composition de Electron

composition electron nodejs chronium

 

Electron embarque plusieurs outils/bibliothèque pour permettre d’avoir les mêmes accès qu’un logiciel développé avec un langage plus adapté et/ou de plus bas niveau :

  • Chronium : c’est le navigateur open source qui sert de base au célèbre Chrome de Google. Il va assurer le rendu visuel de l’application.
  • NodeJS : c’est un environnement d’exécution de code javascript. Il permet l’accès au système de fichier de l’ordinateur, ainsi que le réseau.
  • APIs Natives : permet l’accès aux fonctions natives, propres à chacun des OS.

 

Fonctionnement global

Le développement en est extrêmement simplifié, mais aussi accéléré, car vous aurez accès à plus de 300 000 modules sur NPM. C’est une sorte d’hébergeur de module, qui permet de réaliser certaines tâches. Vous ajoutez donc en quelques secondes de nouvelles fonctionnalité sur votre application.

D’autant plus que vous pouvez ajouter un framework pour le frontend pour structurer votre application : Angular, React, VueJS…

 

Vous allez avoir deux processus différent pour faire fonctionner une application tournant sous Electron :

 

  • Main process

C’est le point d’entrée de votre application. Il va contrôler le cycle de vie de l’application. Vous aurez tout les accès depuis ce processus, via les API native ou de NodeJS. Il peut aussi créer de nouveau processus de rendu, ainsi que de démarrer et de quitter l’application.

Ce processus est unique

 

  • Render process

Il va être responsable de la vue de votre application, par le biais d’affichage de vos pages HTML/CSS. Vous aurez accès au javascript pour gérer les contrôleurs et interactions. Mais attention, pas d’accès direct au système.

Chacun des processus de rendu sont indépendant les uns des autres. Si un crash, il n’affecte pas ses voisins. Il peut être caché, permettant d’exécuter du code en arrière plan.

Ce processus peut être multiple.

 

/!\ L’ensemble des fonctionnalités disponible par l’API de Electron ne sont pas forcement accessible depuis les deux types processus. Certains ne seront garanti que dans un seul des deux type de processus.

 

Communication entre Render et Main process

Electron à mit en place un module, appelé IPC, permettant de réaliser une communication ainsi qu’un échange de données entre main et render process, qui est appelable depuis chacun des processus. Cette communication fonctionne sous forme de canaux, et l’échange est bi-latéral. Celle-ci s’apparente à des sockets.

 

Architecture d’une application Electron

Le schéma suivant montre d’une façon simplifié le fonctionnement de base d’une appli Electron.

Architecture simplifiée
Architecture simplifiée
  1. Le package.json est le point d’entrée de votre application. Il va indiquer à Electron ou est le main process,
  2. Le main.js définit votre processus principal. Il va créer la fenêtre graphique pour y appeler le render process.
  3. Le index.html définit votre vue.
  4. Le module IPC permet l’échange d’informations entre les divers processus.

 

Conclusion

Points positifs

  • Stack web facile à apprendre
  • Dév rapide ( hot reload, console chronium, modules NPM… )
  • Cross-platform

Points négatifs

  • Consommation excessive de RAM
  • Taille du bundle ( ~100Mo pour un simple ‘Hello World !’ )

 

Maintenant que vous voyez le fonctionnement global d’un projet sous Electron, je vous propose d’expérimenter vous même, et de réaliser un traitement de texte basique sur le chapitre suivant.

 

 

Cours web frontend - Angular 8

Chap 1 : Installation des pré-requis

Pour créer le frontend d’une application avec le framework Angular, il va nous falloir installer quelques dépendances nécessaires. Rassurez-vous, rien de bien long 🙃

 

Node.Js & NPM

Pour faire simple, c’est un framework en Javascript permettant de réaliser des serveurs pour le backend. On en a besoin puisqu’il va nous fournir NPM. C’est le gestionnaire de packet pour le web, comme NuGet pour le C#, ou encore PiP pour Python. Il va nous permettre d’installer pleins de librairies nous facilitant le développement de notre application.

 

Vous pouvez le récupérer sur son site https://nodejs.org/en/

Installer la version que vous souhaitez cela importe peu. Il va créer un dossier Node sur le disque C. Vous devrez rajouter ce dossier C:\ProgramFiles\Node\ au PATH des variables d’environnement de votre système d’exploitation, pour que nous puissions utiliser les alias dans la console.

On peut alors tester que tout fonctionne correctement :

C’est OK pour nous, on a bien Node.Js et NPM qui sont accessible.

 

Angular & Angular/Cli

La prochaine étape va être d’installer la librairie Angular. Mais pourquoi alors parler de Angular/Cli ? CLI est une interface de ligne de commande pour Angular, une sorte d’extension. Elle va nous permettre de faciliter la création d’une application Angular par la suite en créant à notre place toute sorte d’objets pré codés, nous permettant alors de gagner un certain temps.

Dans une console on va alors se mettre à la racine du projet duquel on souhaite créer, et exécuter :

  • npm i @angular/cli

 

Vous pouvez voir l’ensemble des packets installé via :

  • npm list –depth=0

L’attribut –depth est facultatif. Il permet de réduire l’arbre des dépendances de l’ensemble des packets pour y voir plus claire

 

Nous voilà OK pour le chapitre suivant, auquel on va pouvoir initialiser notre première application !