Je rage à chaque fois que je saisis un mot de passe fort et que le site m’envoie bouler parce que je n’ai pas de caractère autre qu’alphanumérique.
Essayons quelque chose d’un peu plus smart pour évaluer la robustesse d’un mot de passe
Développeurs, vous savez probablement tout ça, mais continuez à lire parce que la fin vous est adressée
Traduit autrement, voici le nombre de combinaisons qu’on peut tester, et le même chiffre écrit en puissance de deux (arrondi à la décimale inférieure) :
1 €
3,5 × 10^12
2^41,6
10 €
3,5 × 10^13
2^44,9
100 €
3,5 × 10^14
2^48,3
1 000 €
3,5 × 10^15
2^51,6
10 000 €
3,5 × 10^16
2^54,9
100 000 €
3,5 × 10^17
2^58,2
Quand on vous parle ailleurs de bits d’entropie, ça correspond à ces puissances de 2. Avec 1 000 € on peut tester toutes les combinaisons de SHA 256 d’une chaîne aléatoire de 51 bits.
Ok, mais ça me dit quoi ? Une lettre c’est 26 combinaisons, environ 4,7 bits. Si vous ajoutez les majuscules vous doublez le nombre de combinaisons et vous ajoutez 1 bit. Si vous ajoutez les chiffres et quelques caractères spéciaux on arrive à à peine plus de 6 bits.
Petit calcul, en utilisant juste les 26 lettres de l’alphabet, on peut tester toutes les combinaisons de 8 caractères pour moins de 1 €. Vu qu’on aura de bonnes chances de tomber dessus avant d’avoir testé toutes les combinaisons, autant dire que même avec 9 caractères, votre mot de passe ne vaut pas plus de 1 €.
Combien faut-il de caractères pour se trouver relativement à l’abri (c’est à dire que la somme investie ne peut pas tester plus de 1% des combinaisons) ? Ça va dépendre de ce que vous y mettez comme types de caractères. J’ai fait les calculs pour vous :
a-z
a-z A-Z
a-z A-Z 0–9
a-z A-Z 0–9 +-%
1 €
11
9
9
8
10 €
11
10
9
9
100 €
12
10
10
10
1 000 €
13
11
10
10
10 000 €
14
11
11
11
100 000 €
14
12
11
11
Et là magie : 8 caractères, même avec des chiffres, des majuscules et des symboles, ça résiste tout juste à 1 €. Et encore, là c’est en partant du principe que vous choisissez réellement les caractères de façon aléatoire, pas que vous ajoutez juste un symbole à la fin ou que vous transformez un E en 3.
Vous voulez que votre mot de passe résiste à un voisin malveillant prêt à mettre plus de 10 € sur la table ? Prévoyez au moins 10 caractères.
Et là, seconde magie : Si vous mettez 10 caractères on se moque de savoir si vous y avez mis des chiffres ou symboles. La longueur a bien plus d’importance que l’éventail de caractères utilisé.
Maintenant que vous savez ça, tous les sites qui vous imposent au moins une majuscule et un symbole mais qui vous laissent ne mettre que 8 caractères : Poubelle.
Je ne suis pas en train de vous apprendre à faire un mot de passe fort. Vous devriez utiliser un gestionnaire de mots de passe et le générateur automatique qui y est inclus.
Je suis en train d’essayer de rendre honteux tous les développeurs qui acceptent de mettre ces règles à la con sur les sites web dont ils ont la charge : Vous imposez des mots de passe qui sont à la fois imbitables et peu robustes.
Vous voulez faire mieux ?
Regardez dans quelle colonne est l’utilisateur en fonction des caractères qu’il a déjà tapé et donnez-lui un indicateur en fonction de la longueur de son mot de passe.
Moins de 10 € ? mot de passe insuffisant, refusé
Moins de 100 € ? mot de passe faible, couleur rouge
Moins de 1 000 € ? mot de passe moyen, couleur orange
Mot de passe sûr, couleur verte, à partir de 10 000 €
Si vous gérez un site central, par exemple un réseau social public, vous pouvez probablement relever tout ça d’un cran.
Si ça donne accès à des données sensibles, à des possibilités d’achat, à la boite e-mail ou à l’opérateur téléphonique, mieux vaux relever tout ça de deux crans.
Le tout prend probablement moins de 10 lignes en javascript. C’est une honte que vous acceptiez encore d’implémenter des règles à la con « au moins une majuscule, un chiffre et un symbole, voici les symboles autorisés […] ».
Il y a peut-être des erreurs, probablement des mauvais termes, certainement des fautes ou mauvaises formulations. Vous êtes bienvenus à participer en proposant des corrections.
L’idée de base : Tous les mots de passe sont chiffrés. Personne d’autre que vous ne peut les relire sans votre accord. Ni le serveur sur lequel vous les envoyez, ni quelqu’un qui a accès au disque où vous les stockez, ni quelqu’un qui a ponctuellement accès à votre poste de travail.
Chiffrer c’est simple.
Pour chiffrer on a le choix. On va séparer deux catégories principales de chiffrement : les chiffrements symétriques et les asymétriques.
La plupart des gestionnaires de mots de passe ont choisi un chiffrement symétrique (une seule clef secrète qui sert à la fois à chiffrer et à déchiffrer). C’est simple à gérer, rapide à l’exécution, et il n’y a pas besoin de clef de grande taille. Tous ceux que j’ai vu utilisent de l’AES avec une clef de 256 bits. Au moins pour Bitwarden et Keepass, c’est le mode CBC, et un contrôle HMAC avec SHA256 comme fonction de hachage (mais vous pouvez ignorer tous ces détails s’ils ne vous disent rien).
J’ai dit « la plupart des gestionnaires de mots de passe ». Un projet au moins a fait un choix différent. L’outil pass utilise un chiffrement asymétrique (une clef publique et une clef privée, l’une sert à chiffrer et l’autre à déchiffrer). Plus exactement, ils utilisent l’outil GnuPG. Même si le choix de la clef est libre, par défaut on y utilise généralement une clef RSA de 2048 bits. Pass a fait ce choix en considérant le partage de mots de passes comme la fonctionnalité principale. On verra pourquoi quand on parlera partage. Entre temps on va se concentrer sur ceux qui font du chiffrement symétrique.
Dans les deux cas, on est là dans de l’ultra-standard au niveau cryptographie. Je serais étonné de voir autre chose ailleurs (et c’est une bonne chose).
Une clef ? quelle clef ?
Ok, nos mots de passe sont chiffrés mais où est la clef ?
Impossible de demander à l’utilisateur de se rappeler une clef de 256 bits. Ce serait plus de 40 signes entre minuscules, majuscules, chiffres et caractères spéciaux. Même avec une très bonne mémoire, ce serait ingérable à l’usage.
Stocker la clef de chiffrement en clair sur le disque n’est pas beaucoup mieux. Ce serait comme avoir coffre-fort haute sécurité dont on cache la clef sous le paillasson.
Ce qu’on demande à l’utilisateur c’est un mot de passe principal. Vu qu’il va permettre de déchiffrer tous les autres, on va l’appeler « mot de passe maître ». Il faut qu’il soit assez long et complexe pour éviter qu’un tiers ne puisse le deviner ou le trouver en essayant toutes les combinaisons une à une, mais assez court pour pouvoir s’en rappeler et le taper sans erreur.
Le mot de passe maître ne chiffre rien lui-même. Accompagné d’autres paramètres, il sert à calculer une clef de taille suffisante qui, elle, servira au chiffrement décrit plus haut et qu’on va appeler « clef maîtresse ». La fonction qui fait cette opération est dite fonction de dérivation de clef.
Bitwarden utilise le très classique PBKDF2 avec un hachage SHA256. Pour faire simple on prend le mot de passe, on le mélange à une chaîne aléatoire (stockée quelque part pour réutiliser la même à chaque fois), et on opère la fonction de hachage prévue. Normalement ça suffit pour avoir un résultat considéré comme relativement aléatoire et impossible à remonter en sens inverse.
En pratique on cherche aussi à ralentir quelqu’un qui chercherait à tester tous les mots de passe possibles un à un. Pour ça on va simplement répéter l’opération précédente un certain nombre de fois. Chaque itération prend en entrée le résultat de l’étape précédente. Si je fais 10 itérations, il faudra 10 fois plus de temps à un attaquant pour tester toutes les combinaisons. Ici on considère le résultat comme assez confortable à partir de 100.000 itérations.
Keepass utilise une fonction plus récente et considérée comme plus robuste aux possibilités des matériels actuels : Argon2.
Là aussi tout est très classique. Je n’ai pas regardé tous les gestionnaires de mots de passe mais je serais étonné de trouver autre chose que ces deux solutions standards.
On résume
À l’ouverture le gestionnaire de mots de passe vous demande votre mot de passe maître. À partir de ce mot de passe et de paramètres prédéterminés, il utilise une fonction de dérivation de clef et en sort une clef maitresse.
C’est cette clef maitresse qui permet de chiffrer ou déchiffrer vos mots de passe. Celui qui n’a pas accès à votre clef ne pourra rien faire des mots de passe chiffrés sur le disque.
Sécurité
À l’ouverture, le gestionnaire de mot de passe vous demandera votre mot de passe maître que pour calculer la clef maîtresse à l’aide d’une fonction de dérivation de clef. Une fois ceci fait, il garde la clef maîtresse en mémoire et oublie le reste. Quoi qu’il se passe, personne ne connaîtra votre mot de passe maître.
Le logiciel utilise cette clef maîtresse pour chiffrer et déchiffrer vos mots de passe. Cette clef maîtresse n’est jamais écrite nulle part. La plupart des gestionnaires de mots de passe oublieront volontairement cette clef en mémoire après un certain temps d’inactivité, ou à la mise en veille de votre poste de travail. L’idée c’est de limiter le risque de laisser qui que ce soit d’autre que vous y avoir accès. Dans ces cas là, on vous invitera à saisir de nouveau votre mot de passe maître pour retrouver la clef oubliée.
Une fois la clef maîtresse hors de la mémoire, vous n’avez que des blocs chiffrés que personne ne pourra déchiffrer sans le mot de passe maître. Pas même vous. Si vous oubliez votre mot de passe maître, vous ne pourrez plus jamais relire ce que vous avez stocké. Même votre ami qui s’y connait ne pourra rien pour vous.
Ne vous laissez toutefois par leurrer. On parle sécurité, chiffrement, complexité des fonctions de dérivation de clef, mais en réalité tout ça a peu d’importance comparé à votre mot de passe maître. C’est un peu comme un coffre-fort : Discuter du diamètre des barres de renfort n’a aucun intérêt s’il s’ouvre avec une combinaison de trois chiffres seulement.
S’il est possible de trouver votre mot de passe avec un nombre de tentatives limité, tout le reste ne servira à rien. « Limité » dans ce cas, ça dépasse la centaine de milliards de combinaisons. Il vaut mieux un mot de passe maître complexe avec une fonction de dérivation simple qu’un mot de passe maître simple avec une fonction de dérivation complexe.
Changer le mot de passe
Les plus alertes d’entre vous auront remarqué que si tout est déchiffré indirectement à partir du mot de passe, changer le mot de passe fait perdre l’accès à tout ce qui est déjà chiffré.
Quand vous changez votre mot de passe maître, Keepass déchiffre toutes les données en mémoire, calcule la nouvelle clef et rechiffre l’intégralité des données. Même si vous gérez une centaine de mots de passe, c’est quelque chose qui se fait rapidement sans avoir besoin de vous faire patienter longtemps.
Bitwarden utilise lui une clef intermédiaire totalement aléatoire appelée clef de chiffrement. C’est cette clef qui sert en réalité à chiffrer et déchiffrer les données stockées. Elle est elle-même chiffrée, à partir de la clef maîtresse, et stockée à côté des données.
On a donc un mot de passe maître qui sert à calculer une clef maîtresse. La clef maîtresse sert à déchiffrer la clef de chiffrement. La clef de chiffrement sert à chiffrer et déchiffrer les données sur le disque.
Lorsqu’on veut changer de mot de passe il suffit de chiffrer la clef de chiffrement avec la nouvelle clef maitresse. Il n’y a pas besoin de rechiffrer chaque donnée (vu que la clef de chiffrement ne change pas, elle).
L’avantage n’est pas tant dans le temps gagné (peu significatif) mais dans la résistance aux accès concurrents : On peut avoir plusieurs clients qui lisent et écrivent en parallèle des données différentes dans le même trousseau sans crainte que l’un d’eux n’utilise encore une ancienne clef de chiffrement et envoie des données illisibles par les autres.
Et justement, et si je partage ?
Avec ce qu’on a vu jusqu’à présent, si je partage des mots de passe je dois aussi partager la clef de chiffrement utilisée.
Bitwarden permet de partager des mots de passe à un groupe de plusieurs personnes (appelé « organisation »). Au lieu d’être chiffrés avec ma clef de chiffrement personnelle, ces mots de passe sont chiffrés avec une clef de chiffrement dédiée à l’organisation.
Le gros enjeu n’est pas dans le chiffrement mais dans comment transmettre cette clef d’organisation à chaque utilisateur de l’organisation.
Il faut un moyen pour que l’administrateur de l’organisation chiffre la clef d’organisation, me l’envoie sur le serveur d’une façon que seul moi puisse la relire.
Jusqu’à maintenant c’est impossible parce que nous utilisons des clefs symétriques. C’est la même clef qui sert au chiffrement et au déchiffrement. Si l’administrateur pouvait chiffrer avec ma clef, il pourrait aussi déchiffrer tous mes mots de passes personnels et ça c’est inacceptable.
C’est donc ici qu’on reparle des clefs asymétriques RSA. Chacun a une clef publique (diffusée à tout le monde) et une clef privée (garder secrète par chaque utilisateur). La clef publique sert à chiffrer. La clef privée sert à déchiffrer. Tout le monde est donc capable de chiffrer quelque chose avec ma clef publique, mais seul moi pourrait le déchiffrer.
La clef RSA fait 2048 bits mais ne vous laissez pas impressionner, ces 2048 bits sont en fait moins robustes que les 256 bits d’AES.
L’administrateur de l’organisation récupère ma clef publique, chiffre la clef d’organisation à l’aide de ma clef publique, et envoie ça sur le serveur. Quand je voudrais chiffrer ou déchiffrer quelque chose dans l’organisation, je récupère la clef d’organisation chiffrée avec ma clef publique, je la déchiffre avec ma clef privée, et je m’en sers dans mes opérations de chiffrement.
Ok, mais il va me falloir sécuriser ma clef privée. On a déjà les outils pour ça, il suffit de la chiffrer ! Bitwarden la chiffre donc avec la clef de chiffrement, celle dont on a déjà parlé plus haut.
On a donc un mot de passe maître qui sert à calculer une clef maîtresse. La clef maîtresse sert à déchiffrer la clef de chiffrement. La clef de chiffrement sert à déchiffrer ma clef RSA privée. La clef RSA privée sert à déchiffrer la clef d’organisation. La clef d’organisation sert à chiffrer et déchiffrer les données.
Pfiou! Ça semble long et complexe mais tout utilise toujours le même principe et la plupart de ces opérations ne servent qu’à l’initialisation logiciel quand vous le déverrouillez.
Rappelez-vous, votre clef de chiffrement ne change pas quand vous changez votre mot de passe. Pas besoin donc de changer ou rechiffrer vos clefs RSA non plus.
Et Pass alors ?
Pass fait le choix de sauter tout le chiffrement symétrique et de n’utiliser que l’asymétrique. Un dépôt contient les clefs GPG de tous les membres (clefs publiques). Chaque fois qu’un mot de passe est chiffré, il l’est avec toutes ces clefs. Quand un membre veut lire un des mots de passe, il le déchiffre avec sa propre clef privée.
Quand on ajoute un membre, quand on change une clef, il faut tout rechiffrer.
J’aurais évité autant que possible il y a 15 ans, aujourd’hui je suis amoureux des import explicites en début de fichier, sans aucun symbole externe qui ne soit importé explicitement. Pas de symbole chargé ou défini dans un autre fichier magiquement accessible ailleurs, pas même d’import *. Si je m’écoutais en ce moment je voudrais même importer les types de base du langage.
Mon historique PHP et Ruby m’ont longtemps fait voir l’absence de tout ça comme un avantage. Ça n’est vrai qu’avec de très bon IDE. En pratique ça ne permet pas de savoir où est défini le symbole, s’il existe vraiment, ni de gérer correctement les conflits de noms et surcharges locales.
Il y a souvent tellement peu de modules, classes et fonctions externes différentes dans un fichier bien structuré que l’explicite apporte bien plus de bénéfices que de pénibilité. Si on dépasse la dizaine c’est le symptôme que quelque chose ne va pas par ailleurs
Côté syntaxe j’apprécie celle de Python qui montre ce qui est important systématiquement en fin de ligne.
from xxx import A, B, C as D
Les imports Javascript sont pratiques mais la partie la plus significative se retrouve en milieu de ligne, pas toujours là où c’est visuellement le plus identifiable (sans compter la dualité entre import A et import { A })
Soyons fous, on pourrait même importer les objets de base du langage avec un import { String, Integer, Array } from StdLib. On n’en utilise pas plus d’une poignée dans un même fichier. Point bonus si ça permet que "hello", 42, ou [1, 2, 3] soient des raccourcis de syntaxe vers les classes ainsi déclarées en haut de fichier et n’utilisent pas forcément les classes natives du langage.
import { String, Integer } from Stdlib
import { MyArray as Array } from MaLibPerso
import { MACONSTANTE, MaClasse } from MonAutreLibPerso
Quitte à faire une liste de course, pourrait-on faire que les imports avec un chemin absolu « /dir/sub/fichier » référencent la racine du projet et pas la racine du système de fichier ?
Il n’y a que les imbéciles qui ne changent pas d’avis et c’est mon avis depuis toujours
Coluche
J’ai toujours regardé avec dédain les tentatives des dev JS pour contourner l’écriture de CSS mais je commence à considérer que les outils de CSS-in-JS type Emotion sont la bonne solution pour les webapp React.
J’ai été intégrateur, à faire de la belle CSS séparée du code HTML. On finit quand même vite par construire des monstres ou se prendre les pieds dans le tapis dès qu’on fait plus de quelques pages types.
Pour résoudre le problème, éliminons le. C’est ce que proposent les conventions comme BEM. Si je caricature, il s’agit principalement de retirer les sélecteurs CSS un attribuant une ou plusieurs classes spécifiques à chaque contexte. C’est franchement moche mais ça fonctionne.
CSS-Modules va un peu plus loin. Le principe est le même mais on permet au développeur d’utiliser un nommage plus agréable. C’est l’outil de génération qui gère la complexité au lieu du développeur.
J’avoue que j’aime bien CSS-modules. C’était mon favori jusqu’à présent.
Ça revient à juste gérer un fichier par composant en se limitant à des sélecteurs très simples pour ne pas créer de conflits de spécificité. On reste sur du CSS standard et sur une approche proche de mes habitudes historiques. Mieux : L’intégration peut se faire indépendamment du langage de développement de l’applicatif.
C’est top mais ça se base sur des composants qui ne bougent pas beaucoup, dont on connait à l’avance tous les états.
Dès qu’il s’agit de cumuler plusieurs états, le résultat dépend de l’ordre d’écriture dans la CSS. Parfois c’est bien prévu, parfois non.
Dès qu’il s’agit de rendre des choses très dynamiques, il faut de toutes façons sortir des CSS modules. Vous voulez que dans la vue large les items de navigation se colorent au survol en fonction de la catégorie destination déterminée dynamiquement mais qu’ils utilisent la couleur neutre dans la vue réduite destinée aux mobiles ? Vous êtes à poil et il va falloir composer avec d’autres façons d’injecter des CSS, peut-être même tâtonner sur les priorités entre classes.
Les classes utilitaires et CSS atomiques à la Tachyon sont là pour industrialiser en poussant encore plus loin.
J’ai une classe par valeur à appliquer : .ms7-ns applique la septième valeur du catalogue (7) comme taille horizontale maximum (ms pour max-width) si la fenêtre a une taille supérieure au point de rupture « small » (ns pour non-small).
Ça n’offre quasiment aucune abstraction utile (uniformiser les valeurs on a déjà plein d’outils plus efficaces). C’est vite cryptique, lourd, et monstrueux dès qu’on multiplie les valeurs et les points de rupture possibles.
Le seul intérêt par rapport à écrire directement les attributs style c’est que ça permet d’accéder aux media query et aux pseudo-sélecteurs.
Malheureusement non seulement ça ne résout pas les conflits de priorités mais ça les empire. Si je spécialise un composant existant en y ajoutant une classe liée à une directive déjà présente, je joue à la roulette russe. Il faut absolument que mon composant initial prévoit lui-même tous les cas possibles pour savoir quelle classe injecter et ou ne pas injecter. Pas d’alternative.
J’ai vraiment l’impression d’un retour en arrière monstrueux avec ces CSS atomiques, cumuler les défauts sans aucun avantage, et c’est probablement ce qui m’a fait rejeter par principe les CSS-in-JS jusqu’alors.
Les CSS-in-JS c’est finalement pousser la logique de Tachyons un cran plus loin. Quitte à décider de tout dans le code HTML, autant écrire directement les styles à cet endroit là en utilisant la vraie syntaxe CSS et en y ajoutant la possibilité d’accéder aux media query et aux pseudo-sélecteurs.
Emotion c’est ça. On est à la croisée entre le « j’écris tout dans un attribut style » et le « j’attache un module CSS ».
En fonctionnement basique c’est comme un CSS module sans le sélecteur. Je donne les directives en CSS on ne peut plus classiques et j’ai accès aux media query, aux pseudo-sélecteurs et aux animations avec une syntaxe proche de ce que font les préprocesseurs habituels (et en phase avec la direction que prend la syntaxe CSS elle-même).
Je peux directement ajouter le résultat aux classes CSS de mon composant. Il se chargera de générer un nom de classe, de créer la CSS correspondante dans le document, et de lier les deux, comme avec CSS-Modules.
L’exemple est peu parlant. On a juste l’impression d’un CSS-Modules écrit dans le fichier JS.
L’avantage c’est que je ne suis pas limité aux valeurs en dur. Je peux avoir des valeurs dynamiques venant de mon Javascript ou de mon thème, et je n’en limite pas les effets à ce que me permettent les variables CSS.
Je peux aussi réutiliser, composer ou surcharger un élément ou un bloc de styles avec un autre sans risque de conflit de priorité.
Tachyons me donnait l’impression de cumuler les inconvénients, ici j’ai vraiment l’impression de cumuler les avantages.
La seule contrainte c’est que mon code CSS se retrouve dans mes fichiers JS. C’est moche quand c’est dit ainsi mais pour une app en React, on a de toutes façons un fichier par composant HTML et ça a du sens de grouper HTML, JS et CSS lié au composant ensemble quand ils sont fortement liés. C’est d’ailleurs le choix de VueJS.
Ce n’est forcément pas adapté à tout, et si vous voulez rester génériques les CSS-Modules sont à mon avis l’option la plus saine, mais pour un code React je crois que c’est là que je commencerai par défaut désormais.
J’ai toujours été gêné par l’intégration de grosses modifications dans git.
Dans l’idéal on fait une série de modifications autonomes, on les soumet à la revue des pairs puis on les intègre dans les branche principale qui peut partir en production à tout moment.
Ça c’est la théorie. En pratique je fais des erreurs que je ne vois qu’à la fin des modifications. Mes collègues auront de toutes façons des retours sur ce que j’ai poussé en ligne et me demanderont des modifications avant l’intégration finale. Si ce n’est pas le cas au moins une fois sur deux, c’est que nous travaillons mal.
Et là… les ennuis commencent.
Mes modifications ne sont plus autonomes. J’ai des correctifs à la fin. Potentiellement mes modifications précédentes sont donc incomplètes, de mauvaise qualité ou même défaillantes. Si j’intègre mon code à la fin de la revue, je casse toute la belle théorie.
La première pratique c’est d’intégrer le code tel quel sur la branche master. C’est ce qui m’apparait le plus cohérent. Le code de la branche est potentiellement instable mais tous les points d’étape de master sont de qualité. Pour parcourir les modifications de la branche master on ajoute --merges --first-parent histoire de ne pas voir les modifications internes des sous-branches. Ni vu, ni connu mais le débogage de la branche après coup en cas de besoin ne sera pas idéal.
L’alternative est de fusionner en une seule toutes les modifications de la branche lors de son intégration. On perd toute la granularité et ça peut rendre bien plus difficile de tracer l’origine d’une anomalie par la suite, ou de comprendre le pourquoi et le comment d’un changement. C’est encore viable sur 100 voire 200 lignes bien groupées mais ça devient franchement litigieux au delà.
La seule pratique que je réprouve totalement est celle du rebase sans squash. On importe tous les changements directement sur master et on perd totalement la capacité d’avoir un master stable. Ne faites pas ça.
La troisième voie c’est la réécriture de l’historique.
En théorie c’est mal, au moins pour les branches déjà publiées. En pratique tant qu’aucun autre code ne se base dessus, ça ne pose pas vraiment de problèmes. Sur des équipes en entreprise ça se maitrise assez bien. Sur du code open source ça me semble plus litigieux. Github le gère parfaitement dans les pull-request en cours de revue.
Les vrais, les purs, le font en ligne de commande. Je suis admiratif devant ceux qui savent découper une modification ou ajouter un correctif dix changements en arrière dans l’historique sans réfléchir ni tout casser. Techniquement ça ne pose pas vraiment de difficultés mais c’est long, propice aux erreurs, et le moindre faux pas peut faire de gros dégâts irrémédiables. Je ne trouve pas les interfaces graphiques inutiles pour tout ça.
Et là, merci Patrick, gitup vient désormais à ma rescousse. L’interface est simpliste, pas toujours pratique, mais elle fait ce que je n’ai pas vu ailleurs.
Je suis capable de séparer un changement en deux quelle que soit sa position dans l’historique ;
Je suis capable de déplacer un changement en haut ou en bas dans l’historique d’un simple raccourci clavier ;
Je suis capable de faire un correctif, le descendre dans l’historique, puis le fusionner avec le changement initial qu’il faut corriger.
Tout ça graphiquement, avec la possibilité de revenir en arrière quand je veux si jamais je fais des bêtises.
Le projet Lima s’éteint. C’est dommage. Je suis convaincu que les équipes de Lima ont fait tout ce qu’elles pouvaient pour que ça n’arrive pas. Des fois « on n’y arrive pas ». C’est dommage mais c’est ainsi et on doit plutôt remercier les gens d’avoir essayé.
Les appareils concernés vont à terme devenir inutilisables. C’est un bon exemple de « n’utilisez pas d’appareils connectés qui dépendent d’un service centralisé » mais à mon sens la leçon n’est pas celle là.
Je n’aime pas tirer sur l’ambulance mais mon problème est un problème éthique.
What happens if CGC dies ?
What’s good with Lima is that it’s entirely private and decentralized. So Lima can work independently from any servers, and continue managing your data even if our startup dies (disclosure: we don’t plan anything like that)
The only thing we manage on our side of the equations are updates of our app and the web interface of Lima. In case of company crash, we’ll do our best to open source at least the most critical parts of our code, so the community continues improving the solution every night.
La disparition de l’entreprise a été envisagée dès le début de l’aventure (c’est bien) et des éléments de réassurance ont été posés (c’est bien aussi, même si ce n’est que du best effort).
J’ai un problème éthique parce que toutes les équipes de Lima, des fondateurs jusqu’aux développeurs ont accepté de poser ces éléments de réassurance alors qu’ils semblent faux.
En pratique le serveur de l’infrastructure Lima est un composant essentiel et les boitiers vont progressivement arrêter de fonctionner. Ce n’est pas moi qui le dit, c’est Lima eux-mêmes. Là on est dans la tromperie pure et simple par rapport à la promesse affichée.
While your Lima product synchronises with your devices without servers, our servers are still needed to make your devices find each other and establish a connection.
Unfortunately, as our services shut down, your Lima will progressively stop to work.
La promesse de l’open source est similaire. En pratique il est impossible de passer le code open source une fois la société en liquidation. C’est confirmé par les réponses sur Twitter.
C’est simplement légal. Les actionnaires perdent le contrôle de la société et le liquidateur a l’obligation légale de tirer le maximum des possessions de la société. Ça inclut le code source et la propriété intellectuelle. Libérer le code source gratuitement n’est légalement plus possible.
If there’s any way, we will. But unfortunately the complexity of IP law makes it difficult: it is no longer up to us.
Il aurait fallu s’y prendre avant le début des difficultés. Il aurait fallu déposer le code source régulièrement chez un tiers de confiance et s’engager contractuellement avec lui sur une cession de droits qui ne deviendra effective qu’à certaines conditions pré-établies.
Même si la FAQ parle de « do our best », on est dans la tromperie. Il n’est pas imaginable que la question ait été abordée dans la FAQ et que les collaborateurs de l’entreprise aient pu ignorer les enjeux ci-dessus. Ils semblent pourtant ne rien avoir prévu, consciemment, et avoir participé là aussi à un décalage significatif entre le discours et les actions.
J’en veux aux développeurs qui ont participé à ça, et qui vont mettre le doute sur tous les autres.
Développeurs, vous ne devriez pas mettre l’éthique de côté. Vous ne devriez pas apporter votre concours à des sociétés qui trichent, qui trompent, peu importe le degré de coolitude du produit ou du service.
Un des premiers mensonges qu’on vous livre trop souvent avec SCRUM c’est qu’on peut estimer des petites tâches avec bien plus de précision que des grandes, et qu’en conséquence on peut être assez fiable dans l’estimation des une à trois semaines de chaque itération.
Foutaises !
Combien de temps faut-il pour mettre les blousons avant d’aller à l’école ? Mettons 30 secondes si on ne se presse pas. La réalité c’est que ça mettra plus souvent 5 minutes que 30 secondes, et ça c’est si on n’a pas besoin de se battre.
400% de marge d’erreur ? Comment voulez-vous faire un planning avec de telles estimations. Pourtant on est sur une tâche connue, répétée chaque jour. Seule solution, on triche et on compte 2 minutes 30. Même ainsi on a une marge d’erreur de 100%. Hallucinant !
Ce n’est pas un exemple choisi. J’ai le même problème pour terminer la tartine, pour boire le verre d’eau ou pour passer aux toilettes avant de partir, pour descendre dans la rue, pour faire le trajet, pour trouver le badge et passer le portail de l’école, pour montrer ma carte au vigile, pour les 10 mètres dans l’école au milieu des copains et autres parents d’élèves, pour le bisou de bonne journée avant de pouvoir repartir…
Ce n’est pas non plus la faute d’une mauvaise analogie. Estimer une petite tâche est juste impossible parce que le moindre aléa fait tout exploser.
Ajouter un lien sur une page ça prend 30 secondes… sauf si on vous dit de changer l’URL au dernier moment et qu’il faut faire deux fois le travail, sauf si c’est le seul lien à cet endroit et qu’il faut retoucher les règles de style, sauf si le lien passe à la ligne en plein milieu et que visuellement ça ne le fait pas du tout sur ce composant, sauf si l’espace pris fait glisser le bouton qui suit sous le clavier sur un smartphone une fois le clavier déplié, sauf s’il faut partir à la chasse de la bonne URL parce que c’était « ça n’a pas d’impact, on donnera le lien au dernier moment », sauf si on se rend compte qu’il faut mutualiser ce lien avec autre chose ailleurs dans l’application, sauf si ajouter un lien casse le test end-to-end et qu’il faut le réécrire pour faire passer le serveur d’intégration continue au vert, sauf si… pour un simple foutu lien !
Et pourtant, on n’est jamais en retard à l’école. Malgré les aléas infinis à chaque tâche, le projet « aller à l’école » prend 45 minutes à ±15 minutes. Pas plus.
Ce n’est même pas qu’estimer le projet dans son ensemble permet de lisser les risques de dérapages, c’est que le temps que prend chaque tâche dépend de toutes les tâches précédentes et des options qu’il nous reste pour les suivantes.
S’il faut lutter pour terminer le croissant alors on active sérieusement la suite. Si les toilettes s’éternisent je prépare le blouson et le bonnet pendant ce temps. S’il le faut on presse un peu le pas. À l’école, si on arrive dans les derniers, aucun parent d’élève ou camarade ne nous retient dans les dix derniers mètres et le bisou sera vite fait. Si vraiment on est super en retard on peut toujours sortir le vélo ou prendre le tram.
En réalité si SCRUM estime les fonctionnalités unitaires ce n’est pas pour s’engager sur un résultat donné à l’avance, ni même pour mesurer si l’itération a été une réussite ou un succès lors de la rétrospective. C’est uniquement pour savoir où on va dans la boîte de temps qu’on s’est donnée. Rien de plus.
Quand on vous dit que ça permet d’être plus fiable, derrière se cache l’hydre du « on va transformer vos estimations en engagement » voire du « on va ajouter vos estimations une à une et ça donnera la deadline de fin de projet si rien ne change ».
Ami, tu viens d’être éligible à la fibre ou de déménager là où la fibre est présente. Tu cherches un opérateur.
Ne fais pas attention au débit. Si tu viens de l’ADSL ça va être le jour et la nuit quoi que tu choisisses comme offre fibre. Tu auras des offres allant de 200 Mb/s à 10 Gb/s, à comparer à ton ADSL qui se situe quelque part entre 8 et 20 Mb/s en descendant et au mieux 1 Mb/s en montant.
En réalité tu ne verras pas de différence significative au jour le jour entre les offres à 300 Mb/s et les offres à 1 Gb/s. Tu n’atteindras de toutes façons que rarement de tels débits de toutes façons. Ne parlons même pas du 10 Gb/s, là on est dans du marketing.
Regarde tout le reste : la qualité de la box, regarde le prix initial mais aussi si ce n’est pas une offre promotionnelle pour les 12 premiers mois qui va doubler au bout d’un an, regarde les frais d’installation ou de résiliation, regarde s’il y a une offre TV qui te correspond, regarde les délais habituel de l’opérateur pour les installations, regarde la qualité de leur support client, etc. Tout ça a bien plus d’importance que le débit des offres fibre, et te touchera de façon bien plus forte.
La réalité est plus complexe que le dépliant du fournisseur d’accès
On a tous envie de se dire qu’entre 10 Gb/s (10 000 Mb/s) et 300 Mb/s, ça se voit un peu quand même. La réalité est plus complexe. Ce chiffre ne reflète que le débit théorique entre la box et le fournisseur d’accès.
Déjà chez toi : Si tu es sur WIFI, tu peux oublier l’idée d’aller à plus de 500 Mb/s en pratique même en t’asseyant juste à côté de ta box. Pour aller plus loin il faudrait un câble ethernet. Ils sont déjà loin les 10 Gb/s. En réalité sur un appartement un peu bruité, avec un peu de distance, c’est déjà très bien si on arrive à faire du 300 Mb/s en pratique. Ne parlons même pas d’avoir un mur entre le poste informatique et la box. Si c’est pour travailler à partir d’une carte SD tu n’approcheras de toutes façons même pas les 100 Mb/s.
Ensuite en face : Non le serveur d’en face ne te permettra généralement pas d’échanger en Gb/s de toutes façons. Même 300 Mb/s tu ne le trouveras pas si souvent. On en est au point où régulièrement il y a des bisbilles avec Youtube, Netflix et les autres parce que les échanges entre eux et les fournisseurs d’accès ne dépassent pas la dizaine de Mb/s aux heures de pointe.
Et de toutes façons sur l’usage : Les hauts débits se trouvent quand tu télécharges un gros contenu de façon soutenu. Tu envoies des fichiers de quelques Mo ou moins ? le temps sera plus dépendant du nombre de fichiers que de la bande passante disponible. Tu fais de la navigation web ? à ces vitesses le temps d’affichage dépend bien plus du développeur du site que de la capacité de ta ligne.
Et fais attention à SFR : Si tu déménages dans un appartement existant et que ni Orange ni Free ne proposent pas d’offre fibre pour ton appartement, il est probable que ton immeuble soit câblé et non fibré (oui, même si SFR continuera à te dire que c’est de la fibre). Tu peux le vérifier facilement : Si ça ressemble à une prise d’antenne TV, que ça a un diamètre plus proche d’un câble d’antenne TV que d’un petit cable USB, c’est du câble coaxial et pas de la fibre.
Là (coaxial SFR) toutes les installations ne sont pas équivalentes. Certaines montent effectivement jusqu’à 1 Gb/s, d’autres non. Tu auras souvent toutes les peines du monde à obtenir le vrai chiffre de la part de leur service commercial qui te servira du « jusqu’à 1 Gb/s » ad libitum . Bref, acheter une offre plus chère afin d’avoir un plus haut débit théorique et remarquer que c’est finalement bridé par l’installation en place, ça serait dommage.
Je ne dis pas que tu ne dépasseras jamais les 300 Mb/s mais ça ne représentera pas ton quotidien. Même s’il t’arrive de télécharger des contenus vidéos ou des grosses archives à partir d’un ordinateur branché par câble, la différence entre 300 Mb/s et 1 Gb/s, c’est télécharger un DVD complet en environ 100 secondes au lieu de 30. Je doute que l’attente supplémentaire soit de nature à influencer sur le choix de l’offre Internet.
Si vraiment tu veux regarder le débit, regarde le débit montant
Le débit descendant c’est celui que tu utilises pour télécharger quelque chose en provenance d’Internet. C’est celui qui est généralement mis en avant parce que le plus gros des deux.
Celui qui peut t’intéresser c’est le second, qui sert à envoyer des contenus vers Internet. Il doit t’intéresser parce qu’il est généralement bien plus petit.
Ce n’était pas important sur ADSL parce que le débit ne te permettait pas grand chose d’autre que du descendant. Avec la fibre tu vas probablement brancher un Google Drive, un Dropbox, peut-être un logiciel de sauvegarde. Tu vas vouloir envoyer d’énormes photos voire des vidéos ou de monstrueux documents bureautiques pas optimisés. Bref, l’usage va changer et ce serait dommage d’avoir un débit trop ridicule en montant.
Entre le 200 (descendant) / 50 (montant) de SFR et le 300 (descendant) / 300 (montant) de Sosh, tu as beaucoup plus de chances de ressentir la différence de débit montant que la différence de débit descendant (même si 50 Mb/s en montant ça reste 50 fois mieux que ce que tu avais en ADSL, et pas ridicule du tout, donc pas forcément le critère).
Le mainteneur d’un paquet NPM n’a plus eu envie et a donné la main à un tiers. Ce tiers a injecté un code malicieux dans une version publique et potentiellement infecté pas mal de monde. Ça n’a été détecté qu’au bout de deux mois et demi alors que le paquet est utilisé un peu partout.
J’en vois qui lancent des blâmes ou qui se moquent sur l’actualité du paquet NPM malicieux. Ça défoule mais : Faites-vous mieux ? Permettez-moi d’en douter très très fortement.
Le moindre projet React, Symfony ou Rails, c’est une centaine de dépendances directes et indirectes, certaines proviennent de sources dont vous n’avez jamais entendu parler. J’ai listé trois frameworks mais c’est bien la même chose sur les autres langages/technos.
C’est bien le sujet : Sauf si vous avez la taille d’un Facebook/Google ou la criticité d’un Thalès ou d’un état, vous n’avez ni les moyens de passer des années-homme à tout recoder en interne, ni les moyens d’auditer chaque source à chaque mise à jour (si tant est que ça suffise).
Même ceux que j’ai nommé, je ne suis pas certains qu’ils le fassent toujours, sur tous les types de projet. Je suis même assez convaincu du contraire. Le ratio bénéfice/risque n’est juste pas assez important pour ça. Les moyens et les délais ne sont pas dimensionnés pour.
Alors moquez-vous, de ceux qui utilisent NPM, de ceux qui ne contrôlent pas l’ensemble des dépendances, mais vous ne faites probablement pas mieux. Il y a pas mal d’hypocrisie dans les réactions que je vois passer.
Ne blâmez pas non plus le mainteneur d’origine. Lui ne vous a jamais rien promis. C’est même dit explicitement dans la licence « aucune garantie d’aucune sorte ». Ce n’est pas parce que d’autres utilisent son code gratuitement qu’il aurait magiquement des comptes à rendre. En fait avoir passé la main est plutôt quelque chose d’encouragé dans l’open source. S’il n’y avait pas eu cette issue, il aurait plutôt fallu le remercier.
Alors quoi ? Alors rien.
Le problème a été résolu. Si ça arrive trop souvent alors ça changera le ratio bénéfice/risque et la communauté évaluera le fait d’avoir trop de dépendances tierces un (tout petit) peu plus négativement, et ainsi de suite.
La question intéressante que personne ne semble poser c’est celle de l’honnêteté du mainteneur d’origine. A-t-il vraiment passé la main ? et s’il l’a fait, est-ce qu’il en a tiré un bénéfice tout en soupçonnant ce qui pouvait se passer ? C’est à peu près la seule chose qui pourrait à mon sens lui faire porter une quelconque responsabilité.
J’aimerais avoir un Firefox configuré en « anonyme par défaut ». Ça veut dire deux choses :
Un site ne doit pas pouvoir partager ou croiser les données avec un autre ;
Un site ne doit pas pouvoir faire persister des données plus longtemps que la session en cours.
Si je veux garder une authentification permanente ou autoriser des croisements (par exemple pour des SSO), c’est à moi de le demander explicitement.
Ça pourrait être fait par une double préférence liée à chaque domaine, quelque chose du type « autoriser le domaine X à stocker des données persistantes dans ce contexte » et « ne pas isoler le domaine X en fonction de l’origine de la page principale ».
Un site ne doit pas pouvoir partager ou croiser les données avec un autre
Ce premier point est relativement bien couvert. L’extension first party isolation fait exactement ça. En gros tout le stockage (cookies, localstorage, indexeddb) est segmenté par l’origine de la page principale dans l’onglet.
Le composant Facebook inclut dans les pages de LeMonde ne partagera aucune données avec celui inclut dans les pages du Figaro. Il restera l’adresse IP et diverses techniques de fingerprinting, mais ça va un peu limiter.
Je navigue avec depuis des mois, plutôt avec succès. Il y a encore du boulot. Il faut le désactiver temporairement pour faire la configuration initiale de Pocket dans Firefox, ou pour le SSO « se connecter avec google » de quelques sites (pas tous, d’autres fontionnent bien) mais globalement ça passe très bien.
Une fois corrigées les anomalies et ajoutée une façon de désactiver l’isolation site par site, ça sera parfait.
Un site ne doit pas pouvoir faire persister des données plus longtemps que la session en cours
Ce second point est plus compliqué.
J’ai tenté initialement d’utiliser les conteneurs de Firefox pour ça mais tout ce que je peux faire c’est isoler des sites les uns des autres. Au final je me retrouve avec un conteneur par défaut qui contient la majorité du trafic et qui continue à garder mes traces de session en session.
Il y a peu j’ai trouvé l’extension temporary containers. L’idée c’est que, par défaut, le navigateur charge un nouveau conteneur temporaire dédié à chaque fois qu’on navigue vers un nouveau domaine. Ce conteneur et ses données sont détruits dès qu’on ferme l’onglet.
Globalement ça fonctionne mais il y a quelques soucis de performance ressentie (au moins des fermeture/réouverture visibles d’onglet lors des navigations) et si on affecte un site à un conteneur fixe pour éviter de se retrouver à chaque fois sur une page non authentifiée, on perd la capacité de l’utiliser en parallèle dans plusieurs conteneurs différents.
J’ai globalement l’impression d’abuser des conteneurs pour quelque chose qui n’est pas fait pour.
L’extension cookie autodelete a une autre approche. On garde le fonctionnement normal des conteneurs mais, par défaut, l’extension supprime les cookies d’un site dès qu’on ferme tous les onglets qui y mènent. Charge à l’utilisateur de faire des exceptions explicites site par site. Globalement ça fait le job mais ça n’efface ni le localstorage ni l’indexeddb, ne parlons même pas du tracking par cache HTTP.
Je trouve ça dommage. Intuitivement j’aurais pensé que supprimer des données était plus facile à faire pour le navigateur que créer une isolation supplémentaire entre les sites.
Suis-je le seul à chercher un tel niveau d’isolation ?