Devoxx FR 2023 – Hidden security features of the JVM – everything you didn’t know and more par Steve Poole
Première conférence à laquelle je vais pour cette session de Devoxx France parle de sécurité dans le JVM par Steve Poole.
Le Security Manager est déprécié mais la JVM a un design fantastique pour la sécurité.
Tout d’abord, pourquoi se soucier de la sécurité ?
Première conférence à laquelle je vais pour cette session de Devoxx France parle de sécurité dans le JVM par Steve Poole.
Le Security Manager est déprécié, mais la JVM a un design fantastique pour la sécurité.
Tout d’abord, pourquoi se soucier de la sécurité ?
- Le crime cyber atteint 460 milliards ! en croissance de 50% / an.
- 90% d’une application est fait de librairie tierce ou de composants open source qui peuvent être vulnérables.
Il y a un grand nombre de vecteurs d’attaque : est-ce que changer un fichier peut mettre en danger tout le système ? Changer la variable système JAVA_OPTS ? Ajouter -Xverify=none
? Peut-on changer le bytecode ? Corrompre la heap ? Charger de code malicieux ?
Pour répondre à ces questions, voyons comment fonctionne la JVM et ses différentes lignes de défense contre les attaques (exploit).
La première ligne de défense est la nature même de la JVM :
- Pas d’accès direct à la mémoire
- Pas de pointeurs
- Pas d’accès direct à l’host
- Pas de threading « physique » : une abstraction fournie par le JVM à la place
- Pas d’accès direct au CPU
La deuxième est dans les propriétés non spécifiées de la JVM :
- GC: accéder à la heap est compliqué, y trouver un objet encore plus.
- Virtual Threads évite l’accès à des fonctionnalités bas-niveau de threading et sont donc plus sécurisés.
- JIT : bytecode verification, random address pour la génération de code compilé, change le code généré en continu. A cause de ça, il est difficile de modifier le code en cours d’exécution depuis l’extérieur de la JVM (exploit).
La troisième est le bytecode: stackbased, pas de registre, simple, vérifié au chargement et à la compilation par le JIT. Il est donc difficile de créer du bytecode vulnérable
Quatrième ligne de défense : le classloader
- Sépare le code de différente source
- Permet des vérifications supplémentaires si nécessaire
On revienst ensuite sur quelques mauvaises idées à éviter d’utiliser dans son code :
- Java a la capacité de charger do code distant à chaud : toujours une mauvaise idée (cf Log4Shell).
- La sérialisation Java est une des fonctionnalités les plus vulnérables car le format de la classe est définit dans le stream de donnée et pas par la classe qui est sérialisés. En changeant le stream à déserialiser, cela permet de charger n’importe quelle classe. Même si la deserialization va planter, la classe malicieuse sera quand même chargée.
ysoserial est un outil qui permet de générer des exploits via une chaîne de deserialization (gadget chain)
Il existe des solutions pour résoudre ou limiter les risques de la sérialisation Java :
- Serialization filter
- Java modules (mais personne ne les utilise dans la salle) permet de réduire la surface d’attaque en réduisant le nombre de classe utilisable
- JLink permet aussi de réduire la surface d’attaque en ne gardant que les modules de la JVM utilisés par une application
- JAR sealing: tout le code d’un package doit venir du JAR qui le contient
Si on compile une application Java en image native via GraalVM : plus de réflexion (ou limité à une liste de class), vérification au build, pas de chargement dynamique des classes mais memory layout fixe, code converti une seule fois et une JVM fallback existe (il est possible de la désactiver).
Maven Central réduit le risque d’attaque via les dépendances : ownership of domain, … En cours : note de sécurité sur les dépendances.
Nous devons aussi agir en tant que développeur : encore 33% des versions de Log4j téléchargées sont vulnérables !
Pour 96% des téléchargements de librairies vulnérables, il y a un fix sur une version supérieure !