Le post mortem d'event stream – Qui est responsable ?

Il y a deux semaines, nous revenions sur l’affaire event-stream. Comme promis, il est temps de faire le point sur les erreurs commises par les uns et les autres impliqués dans cette histoire.
Mon avis est évidemment subjectif, mais j’espère vous transmettre quelques idées pour mieux vous faire votre avis.

Le point de vue du créateur : Dominic Tarr

Ayrton Sparling, le lanceur d’alerte, lui demande directement pourquoi il a donné accès au repo à l’inconnu right9ctrl. Dans le détail, il a accès au repo GitHub ainsi qu’au package npm. Dominic lui a donné ces accès suite à un mail qu’il a jugé légitime. Il n’a évidemment plus les droits pour publier sur npm et ne peut donc faire de nouvelle version.
Dominic se défend en indiquant qu’il n’utilise plus le module depuis des années et qu’il n’a aucun intérêt à maintenir ce module. Des mécontents lui demandent de contacter le support npm pour qu’ils règlent le problème de leur côté, mais il est sur la défensive et leur demande de le faire eux-mêmes s’ils veulent “participer à la maintenance” selon ses mots.
À noter que son projet est sous licence MIT, et qu’il ne garantit donc rien (“THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND”).

Les propositions de Dominic

Tweet de Dominic
Quelques jours plus tard, l’affaire a fait grand bruit, il publie un gist pour détailler son point de vue. Il explique qu’il a déjà partagé ses droits de publication précédemment sans que ça ne pose aucun problème, c’est d’ailleurs le point de vue de certains pour développer l’open source.
L’autre souci qu’il dénonce est que nos projets dépendent de plus en plus de librairies externes, c’est d’ailleurs une critique courante de l’écosystème JavaScript. Ces librairies de quelques lignes parfois pouvant ne plus être maintenues par des personnes qui ont perdu l’intérêt pour le sujet, qui sont en burnout ou qu’ils n’utilisent tout simplement plus.
Dominic propose deux solutions :

  1. Payer les mainteneurs pour être sûrs qu’ils tiennent à jour nos dépendances
  2. Participer directement à la maintenance des projets dont vous dépendez

Certains ont essayé d’ajouter des badges de dons (avec Patreon par exemple) pour recevoir un petit quelque chose pour le travail fourni. Je ne crois pas que beaucoup en bénéficient réellement.
Mais de toute manière, est-ce que ces propositions permettraient réellement d’éviter du code pirate ?
Voici par exemple un bout de code qui lance une requête HTTP :

const i = 'gfudi';
const k = s => s.split('').map(c => String.fromCharCode(c.charCodeAt() - 1)).join('');
self[k(i)](url);

Auriez-vous été capable de comprendre ce que ce code faisait réellement ?

Autres propositions

Les débats ont continué dans les commentaires suite à l’archivage du repo par Dominic.
Certains suggèrent de n’utiliser que des dépendances dans lesquelles on a confiance, qu’on doit faire plus attention à notre gestion de paquets (lockfiles, fixer les versions utilisées (dependency pinning), builds déterministes) ou bien d’utiliser seulement des paquets audités…
Il existe également des services (SonatypeSnyk) pour monitorer nos dépendances et réagir rapidement lorsque des vulnérabilités sont découvertes. Ils requièrent cependant une action manuelle lors de la découverte d’une faille (par ces services) ainsi qu’une action de notre part pour corriger le problème.
Pour moi, ces propositions ne résolvent pas le problème à la source. Rien n’empêcherait réellement l’inclusion de code fallacieux, en particulier dans du code obfuscé.

Qu’en pensent les big players ?

Ces grosses entreprises qui promeuvent l’open source ont subi de plein fouet cette attaque. J’aurai souhaité une réaction de leur part, leurs outils dépendent de nombreux modules dont certains ne sont pas maintenus et sont totalement susceptibles à ce genre d’attaques.
À ma connaissance, aucune n’a communiqué sur le sujet. Ils ne semblent pas mieux préparés que nous à ces problèmes.

C’est la faute de npm

Le gestionnaire de dépendances Node.js permet à n’importe qui de publier des modules publics. C’est une entreprise privée qui ne contrôle pas ce qu’ils partagent. Il leur est déjà arrivé de bloquer des versions de modules fallacieux auparavant, mais ce sont des alertes remontées par des utilisateurs.
Ils ont publié un article à propos de l’incident, mais ne semblent pas vouloir en faire plus pour éviter que cela ne se reproduise.

Comment corriger ce problème à la source ? Le Principe de moindre privilège

Ces attaques ne pourront pas être empêchées, notre seul levier est de limiter les impacts d’une attaque réussie.
Toutes les solutions que nous avons explorées jusqu’à présent ne prennent pas en compte quelque chose d’important : un module externe ne devrait pas avoir accès aux clés privées de notre disque.

Le principe de moindre privilège (POLA en anglais) est un principe qui stipule qu’une tâche ne doit bénéficier que de privilèges strictement nécessaires à l’exécution du code menant à bien ses fonctionnalités. En d’autres termes, une tâche ne devrait avoir la possibilité de mener à bien que les actions dont l’utilité fonctionnelle est avérée.

Définition de l’ANSSI
Dans le cas de flatmap-stream, le module n’avait ni besoin d’un accès au file system, ni d’accès internet. Il a bénéficié d’un surplus d’autorité.
POLA, only the authority you need and no more!
La question est donc : comment implémenter ce principe ? Ou dans d’autres termes : comment limiter le scope des actions de nos modules ?
C’est une problématique bien connue dans le monde Linux et une des raisons d’être de Docker (voir les capabilities Linux).

Isoler JavaScript : les Realms

Pour éviter tout effet de bord nuisible, il faudrait un mécanisme pour pouvoir exécuter du code JavaScript dans un environnement à part (bac à sable).
C’est exactement ce qui est proposé au TC39, le comité qui définit la spécification d’ECMAScript, le standard que suit JavaScript. On parle de Realms.
Avec un petit peu d’imagination, voilà ce que cela pourrait donner à terme :

const addHeader = require('./addHeader', { fs, https })
// pourquoi cette dépendance a besoin d'un accès au file system et au réseau ?
const addFooter = require('./addFooter')
// ça a l'air ok, il n'a besoin de rien

Cela permettrait d’éliminer l’autorisation par défaut et donc d’éviter de donner des droits non nécessaires à des fonctions basiques. Ainsi, même si on se retrouve avec un paquet corrompu, il y a peu de chances que des actions dangereuses soient effectuées.

Conclusion

Le plus choquant est qu’il est aujourd’hui impossible de se protéger de cette faille, elle est peut-être déjà utilisée sur plusieurs paquets dont vous dépendez. Et ça n’est pas seulement vrai pour les modules npm, d’autres langages possèdent ce genre de failles.
Je suivrai l’évolution des Realms et d’autres solutions éventuelles et vous tiendrai informé si quelque chose de viable apparaît.
Espérons en tout cas que d’autres problèmes plus graves n’apparaissent…


Si vous souhaitez en savoir plus sur POLA, je vous invite à lire cet article dont je me suis librement inspiré.
Et une vidéo pour aller plus loin à propos des Realms en JS.
Dernier lien, Dominic a participé à un podcast où il a partagé son histoire et sa perspective de l’histoire d’event-stream.
 

En apprendre plus :

Auteur/Autrice

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

%d blogueurs aiment cette page :