Catégorie : navigateurs et API

  • Fire­fox, « anonyme par défaut »

    J’ai­me­rais avoir un Fire­fox confi­guré en « anonyme par défaut ». Ça veut dire deux choses :

    1. Un site ne doit pas pouvoir parta­ger ou croi­ser les données avec un autre ;
    2. Un site ne doit pas pouvoir faire persis­ter des données plus long­temps que la session en cours.

    Si je veux garder une authen­ti­fi­ca­tion perma­nente ou auto­ri­ser des croi­se­ments (par exemple pour des SSO), c’est à moi de le deman­der expli­ci­te­ment.

    Ça pour­rait être fait par une double préfé­rence liée à chaque domaine, quelque chose du type « auto­ri­ser le domaine X à stocker des données persis­tantes dans ce contexte » et « ne pas isoler le domaine X en fonc­tion de l’ori­gine de la page prin­ci­pale ».


    Un site ne doit pas pouvoir parta­ger ou croi­ser les données avec un autre

    Ce premier point est rela­ti­ve­ment bien couvert. L’ex­ten­sion first party isola­tion fait exac­te­ment ça. En gros tout le stockage (cookies, local­sto­rage, indexeddb) est segmenté par l’ori­gine de la page prin­ci­pale dans l’on­glet.

    Le compo­sant Face­book inclut dans les pages de LeMonde ne parta­gera aucune données avec celui inclut dans les pages du Figaro. Il restera l’adresse IP et diverses tech­niques de finger­prin­ting, mais ça va un peu limi­ter.

    Je navigue avec depuis des mois, plutôt avec succès. Il y a encore du boulot. Il faut le désac­ti­ver tempo­rai­re­ment pour faire la confi­gu­ra­tion initiale de Pocket dans Fire­fox, ou pour le SSO « se connec­ter avec google » de quelques sites (pas tous, d’autres fontionnent bien) mais globa­le­ment ça passe très bien.

    Une fois corri­gées les anoma­lies et ajou­tée une façon de désac­ti­ver l’iso­la­tion site par site, ça sera parfait.


    Un site ne doit pas pouvoir faire persis­ter des données plus long­temps que la session en cours

    Ce second point est plus compliqué.

    J’ai tenté initia­le­ment d’uti­li­ser les conte­neurs de Fire­fox 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 conte­neur par défaut qui contient la majo­rité du trafic et qui conti­nue à garder mes traces de session en session.

    Il y a peu j’ai trouvé l’ex­ten­sion tempo­rary contai­ners. L’idée c’est que, par défaut, le navi­ga­teur charge un nouveau conte­neur tempo­raire dédié à chaque fois qu’on navigue vers un nouveau domaine. Ce conte­neur et ses données sont détruits dès qu’on ferme l’on­glet.

    Globa­le­ment ça fonc­tionne mais il y a quelques soucis de perfor­mance ressen­tie (au moins des ferme­ture/réou­ver­ture visibles d’on­glet lors des navi­ga­tions) et si on affecte un site à un conte­neur fixe pour éviter de se retrou­ver à chaque fois sur une page non authen­ti­fiée, on perd la capa­cité de l’uti­li­ser en paral­lèle dans plusieurs conte­neurs diffé­rents.

    J’ai globa­le­ment l’im­pres­sion d’abu­ser des conte­neurs pour quelque chose qui n’est pas fait pour.

    L’ex­ten­sion cookie auto­de­lete a une autre approche. On garde le fonc­tion­ne­ment normal des conte­neurs mais, par défaut, l’ex­ten­sion supprime les cookies d’un site dès qu’on ferme tous les onglets qui y mènent. Charge à l’uti­li­sa­teur de faire des excep­tions expli­cites site par site. Globa­le­ment ça fait le job mais ça n’ef­face ni le local­sto­rage ni l’in­dexeddb, ne parlons même pas du tracking par cache HTTP.

    Je trouve ça dommage. Intui­ti­ve­ment j’au­rais pensé que suppri­mer des données était plus facile à faire pour le navi­ga­teur que créer une isola­tion supplé­men­taire entre les sites.

    Suis-je le seul à cher­cher un tel niveau d’iso­la­tion ?

  • Après la seconde guerre, le web et le mobile

    La seconde guerre des navi­ga­teurs est sur le point d’être termi­née.

    Pour sché­ma­ti­ser, les gens utilisent Safari sur iPhone et iPad — ils n’ont pas le choix. Partout ailleurs il n’y a quasi­ment plus que Chrome. Objec­ti­ve­ment il faut avouer que le logi­ciel est excep­tion­nel, et évolue constam­ment.

    Fire­fox est en baisse lente mais constante, avec désor­mais moins de 10 % du trafic en Europe. Même le fleu­ron de Micro­soft installé par défaut sur plus de 80 % des postes de travail récents, Edge, ne dépasse pas les 3 %.

    On en est au point où quand vous lancez une appli­ca­tion mobile, c’est en réalité parfois les moteurs de Chrome ou de Safari qui fonc­tionnent en arrière plan. Même les versions légères de Fire­fox mobile sont de simples surcouches à Chrome et Safari.


    La guerre des navi­ga­teurs est termi­née et nous l’avons perdue.

    Nous l’avons perdue parce que nous avons aban­donné le futur de l’in­for­ma­tique person­nelle — le web et le mobile.

    L’es­sen­tiel du parc est contrôlé par une régie publi­ci­taire dont le modèle écono­mique est de surveiller et régen­ter tout ce que vous faites sur vos appa­reils. Google et Chrome c’est ça.

    Les 15 à 20% restant sont des appa­reils premium, pour une élite qui peut se les offrir. En échange d’un peu de vie privée, l’en­tre­prise contrôle tota­le­ment les appa­reils et ce qu’elle nous y auto­rise à faire ou non, en fonc­tion de ses inté­rêts commer­ciaux et de la morale nord-améri­caine. Il n’y aura pas d’al­ter­na­tive.


    Aujourd’­hui nous avons déjà plus ou moins aban­donné notre vie privée et/ou notre liberté d’ac­tion sur nos appa­reils. Nous avons aban­donné tout ça mais nous savons que nous avons des portes ouvertes : Il existe des alter­na­tives, au cas où.

    Le problème c’est que nos navi­ga­teurs ont tous 20 ans. Les moteurs on telle­ment évolué qu’ils n’ont proba­ble­ment plus grand chose à voir avec le code de 1998 mais ce qu’on y a fait est telle­ment complexe et demande de telles ressources que personne n’a rien créé de tota­le­ment neuf depuis.

    Même aujourd’­hui, évoluer à la même vitesse que Chrome est loin d’être facile. Il faut des compé­tences diffi­ciles à trou­ver, des ressources finan­cières signi­fi­ca­tives et quasi­ment impos­sible à renta­bi­li­ser.

    Si demain Chrome ou Safari décident d’im­plé­men­ter plus de choses derrière leurs murs sans les parta­ger en open source, cloner un ancien moteur et rattra­per tout ce qu’ils auront fait entre temps risque d’être mission impos­sible.

    Ne parlons même pas du jour où Chrome aura réel­le­ment 80 % du marché et où ils se permet­tront d’avan­cer sans coor­di­na­tion avec quiconque. On n’en est déjà pas si loin d’une certaine façon.

    Le résul­tat c’est que nous avons besoin d’Opera, Fire­fox et Edge, aujourd’­hui, même si ce n’était que pour forcer Chrome et Safari à conti­nuer à jouer le jeu. Ceux qui ont connu la première guerre des navi­ga­teurs savent de quoi on parle. On joue un peu l’ave­nir du web et du mobile. Rien que ça.


    Pourquoi dis-je tout ça ? Parce qu’aujourd’­hui vous utili­sez Chrome, peut-être Safari. Je comprends : Ça fonc­tionne (très bien). C’est confor­table (très).

    Et si vous tentiez de nouveau Fire­fox ?

    Oui, par le passé c’était plus lourd que Chrome. Je ne vous garan­tis pas que le ressenti sera exac­te­ment le même mais la perfor­mance et la consom­ma­tion en ressources est désor­mais objec­ti­ve­ment simi­laire, assez pour que ce ne soit pas la vraie ques­tion.

    Oui, parfois il y a des sites qui fonc­tionnent mieux sous Chrome, ou qui n’im­plé­mentent pas telle ou telle fonc­tion­na­lité annexe ailleurs que sous Chrome. C’est rare mais ça arrive. Il reste que c’est la poule et l’œuf, ils se le permettent parce que vous utili­sez Chrome. Votre vie privée et votre liberté méritent bien un peu de mili­tan­tisme, non ?

    Bref, je ne dis pas que c’est mieux, mais au moins ce n’est pas signi­fi­ca­ti­ve­ment moins bien. Les diffé­rences sont surtout dans les préju­gés et les habi­tudes.

    Le vrai problème c’est le chan­ge­ment. Quand on change, la moindre micro diffé­rence sans impor­tance peut prendre des propor­tions gigan­tesques pour vous convaincre que non, ça ne le fera pas. Il faut résis­ter, deman­der de l’aide si besoin (parce que non, s’il y avait des problèmes sérieux ça se saurait, et ce n’est pas le cas), et tenter de ne pas lancer Chrome pendant un mois. Pas du tout, pour être en immer­sion, sinon la résis­tance au chan­ge­ment pren­dra l’avan­tage.

    N’al­lez pas me dire que vous êtes vieux et sclé­rosé intel­lec­tuel­le­ment au point de ne pas vaincre cette résis­tance au chan­ge­ment… Et si vous essayiez ?

  • Comment on fait de la crypto dans le navi­ga­teur ?

    Faire de la cryp­to­gra­phie dans le navi­ga­teur se révèle bien plus simple que prévu.

    Lais­sez tomber les portages de libso­dium & co. Quasi­ment tous les navi­ga­teurs supportent désor­mais une API native dédiée. Seul IE11 ne le fait pas tota­le­ment mais il a au moins le mini­mum qu’est la géné­ra­tion de nombres réel­le­ment aléa­toires. Ceux qui veulent vrai­ment pour­ront complé­ter l’im­plé­men­ta­tion d’IE11 avec un poly­fill sans risquer de problème de sécu­rité.

    Il y a plein de jolis exemples sur qnimate mais certaines choses datent un peu. J’ai tenté de résu­mer ici pour ceux que ça inté­resse. Ici pour du déchif­fre­ment à partir d’une clef secrète.

    Avant-propos

    Je ne suis pas un expert en chif­fre­ment et ce genre de choses est toujours à manier avec précau­tion. Si vous faites quelque chose de sérieux, ne vous conten­tez pas d’exemples et embau­chez quelqu’un qui sait.

    Rien que choi­sir l’al­go­rithme perti­nent demande de savoir ce qu’on fait. AES-CTR semble perti­nent pour mon cas d’usage où n’ai pas besoin de véri­fier l’au­then­ti­cité du message, où je n’ai pas envie de me colti­ner les ques­tions de padding, et où je serai heureux de profi­ter des multiples cœurs des smart­phones.

    Si l’al­go­rithme choisi ou autre chose vous dérange et que vous en savez plus que moi, n’hé­si­tez pas à commen­ter.

    Récu­pé­rer une clef

    Le plus simple est de récu­pé­rer direc­te­ment une clef au format JSON Web Key (en gros la clef en base64url plus un peu de méta­don­nées). Dans ce cas il suffit de passer par importKey :

    const crypto = window.crypto.subtle;
    
    const jwk = {
      "kty": "oct",
      "use": "enc",
      "k": "SDRSTgdOpUGfgn3iAwiC1cpzsevLM98r_6ehMXlK1Gk",
      "alg": "A256CTR"
    };
    const algo = {name: "AES-CTR"};
    const exportable = false;
    const usage = ["decrypt"];
    
    const key = await crypto.importKey("jwk", jwk, algo, exportable, usage);
    Déri­ver une clef

    Si on veut partir d’une phrase secrète mémo­ri­sable et non d’une clef complète, on commence par créer une clef tempo­raire et on utilise un algo­rithme de déri­va­tion comme PBKDF2.

    Malheu­reu­se­ment pour créer cette première clef il faut passer par un TextEn­co­der et ArrayBuf­fer. peut toujours déri­ver la clef à partir de là. TextEn­co­der n’existe pas sous Edge et IE11, il vous faudra utili­ser une fonc­tion comme uniba­bel qui fait ça pour vous.

    const crypto = window.crypto.subtle;
    const encoder = TextEncoder();
    
    const passphrase = "l'eau ça mouille, le feu ça brûle";
    const buffer = encoder.encode( passphrase );
    const d_algo =  {name: 'PBKDF2'};
    const d_exportable = false;
    const d_usage = ['deriveBits', 'deriveKey'];
    const d_key = await crypto.importKey('raw', buffer, d_algo, d_exportable, d_usage);
    
    const deriv = { 
      name: 'PBKDF2',
      salt: encoder.encode( "c'est le week-end !" ),
      iterations = 25,
      hash: 'SHA-256',
    };
    const algo = {name: "AES-CTR", length: 256}; 
    const exportable = false; 
    const usage = ["decrypt"];
    
    const key = await crypto.deriveKey(deriv, d_key, algo, exportable, usage);

    La sécu­rité de tout ça dépend de la longueur et de l’uni­cité de votre phrase secrète initiale. À vous de trou­ver le bon compro­mis entre la sécu­rité et la puis­sance des smart­phones qui risquent d’uti­li­ser votre code. Le 25 ici est pure­ment arbi­traire et le temps de calcul néces­saire est propor­tion­nel.

    Déchif­frer

    Déchif­frer n’est pas plus diffi­cile.

    Le vecteur d’ini­tia­li­sa­tion (iv) et la donnée chif­frée (encryp­ted) sont atten­dus sous forme d’Ar­rayBuf­fer. Il faudra de nouveau passer par uniba­bel ou une autre solu­tion si vous avez ça sous forme de chaîne binaire ou codé en base64.

    Le résul­tat de decrypt() vous est retourné sous la même forme. S’il est petit le plus simple est d’uti­li­ser TextDe­co­der ou uniba­bel. Si vous avez quelque chose de plus volu­mi­neux vous pouvez aussi passer par un Blob et un FileRea­der.

    const crypto = window.crypto.subtle;
    const decoder = TextDecoder
    
    const key = ...
    const iv = ...
    const encrypted = ...
    
    const algo = { name: 'AES-CTR', iv: iv }
    const buffer = await crypto.decrypt(alg, key, encryted);
  • Dis Mozilla, et si tu écou­tais tes utili­sa­teurs ?

    La première fois que Mozilla a imaginé de mettre des publi­ci­tés dans la page « nouvel onglet ». Quand on réflé­chit à des pistes nouvelles, parfois on s’égare. Pas de problème. La conclu­sion de la commu­nauté était que non, il ne fallait pas de publi­ci­tés dans les nouveaux onglets. Même en opt-out, même en respec­tant le « do not track ». À partir de là on sait.

    La seconde fois, quand Mozilla a parti­cipé à un contexte promo­tion­nel pour une série TV, on a bien voulu parler de faux pas. L’exer­cice était limité, la réponse a toute­fois été sans appel : Non.

    Un verre ça va, trois verres bonjour les dégâts. Après ces deux tenta­tives, remettre le couvert une troi­sième fois avec une idée quasi iden­tique à la première, ça commence à être un problème dont il faut parler, plus des erre­ments.

    Mozilla, je comprends le problème de finan­ce­ment mais si tu n’écoutes pas tes utili­sa­teurs, tout le finan­ce­ment imagi­nable se révé­lera bien vain.

  • [Lecture] The whole web at maxi­mum FPS: How WebRen­der gets rid of jank

    Proba­ble­ment le meilleur article que j’ai vu sur le fonc­tion­ne­ment d’un navi­ga­teur moderne avec les diffé­rentes étapes et l’uti­li­sa­tion du GPU, par Lin Clark. À lire.