Applications Web isolées

Le Web est une plate-forme d'application vraiment unique. Les applications qui en découlent sont instantanément accessibles sur n'importe quel système d'exploitation, sans qu'il soit nécessaire de modifier le code ni de compiler. Chaque fois qu'un utilisateur accède à votre application, il dispose toujours de la version la plus récente. Elles sont installables et peuvent fonctionner hors connexion. Elles sont très performantes et peuvent être partagées très facilement avec un simple lien. Créez une application Web, et elle fonctionnera partout.

Étant donné que le Web vise à être sûr et sécurisé par défaut, son modèle de sécurité doit être très conservateur. Toutes les nouvelles fonctionnalités ajoutées doivent être sûres pour un utilisateur occasionnel qui pourrait les découvrir accidentellement via une URL. Nous appelons ce modèle de sécurité drive-by web. Bien que cela soit idéal pour de nombreuses applications et puisse être sécurisé à l'aide des Règles de sécurité du contenu et de l'isolation multi-origine, cela ne fonctionne pas pour tous les cas d'utilisation. Un certain nombre d'API très importantes et très puissantes, comme Direct Sockets et Controlled Frame, dont les développeurs ont besoin, ne peuvent pas être suffisamment sécurisées pour le lecteur par le Web.

Pour ces applications, il n'existe actuellement aucune option permettant de créer des applications sur le Web. Pour d'autres, le modèle de sécurité du Web n'est peut-être pas assez conservateur. Ils ne partagent peut-être pas l'hypothèse selon laquelle le serveur est fiable et préfèrent plutôt les applications autonomes discrètement versionnées et signées. Un nouveau modèle de sécurité à haut niveau de confiance est nécessaire. Les applications Web isolées (AWI) fournissent un modèle d'application isolé, groupé, versionné, signé et fiable, basé sur la plate-forme Web existante, pour permettre à ces développeurs de créer des applications.

Un spectre de confiance sur le Web

Vous pouvez considérer la sécurité et les fonctionnalités sur le Web comme un spectre.

Illustration montrant le spectre de confiance sur le Web. À gauche, un globe représentant le Web drive-by. Au milieu, "Progressive Web Apps". À droite, un bocal à poissons avec un poisson rouge à l'intérieur, représentant les applications Web isolées. Une ligne noire continue relie les trois icônes horizontalement, et une ligne rouge en pointillés sépare les applications Web progressives des applications Web isolées.

Le modèle de sécurité drive-by web, à gauche, présente le niveau de confiance le plus faible, car il doit être le plus accessible et, par conséquent, il dispose du moins d'accès au système d'un utilisateur. Les applications Web installées dans le navigateur, au milieu, bénéficient d'un peu plus de confiance et peuvent s'intégrer un peu plus profondément dans le système d'un utilisateur. En général, les utilisateurs peuvent passer des versions Web des applications aux versions installées dans le navigateur sans problème.

Ensuite, il y a les applications Web isolées à haut niveau de confiance.

Elles agissent et se comportent davantage comme des applications natives, et peuvent accéder à des intégrations système profondes et à des fonctionnalités puissantes. Les utilisateurs ne peuvent pas passer de l'un à l'autre ni au drive-by-web. Si vous avez besoin de ce niveau de sécurité ou de ces fonctionnalités, vous ne pourrez pas revenir en arrière.

Lorsque vous essayez de déterminer le modèle de sécurité à adopter, choisissez par défaut celui qui offre le niveau de confiance le plus faible, comme une application Web progressive. Vous bénéficierez ainsi de la plus grande portée, vous aurez le moins de problèmes de sécurité à gérer vous-même et vous serez le plus flexible pour vos développeurs et vos utilisateurs.

Conception sécurisée

Les applications Web isolées fournissent un modèle de sécurité hautement fiable pour les applications Web. Pour ce faire, il faut repenser certaines hypothèses que le drive by web fait sur la confiance. Les composants Web de base, tels que les serveurs et le DNS, ne peuvent plus être explicitement approuvés. Les vecteurs d'attaque qui peuvent sembler plus pertinents pour les applications natives deviennent soudainement importants. Ainsi, pour accéder au nouveau modèle de sécurité à haut niveau de confiance fourni par les AWI, les applications Web doivent être empaquetées, isolées et sécurisées.

Empaqueté

Les pages et les ressources des applications Web isolées ne peuvent pas être diffusées à partir de serveurs actifs ni récupérées sur le réseau comme les applications Web normales. Pour accéder au nouveau modèle de sécurité à haut niveau de confiance, les applications Web doivent regrouper toutes les ressources dont elles ont besoin pour s'exécuter dans un WebBundle signé. Les bundles Web signés regroupent toutes les ressources nécessaires à l'exécution d'un site dans un fichier .swbn, en les concaténant avec un bloc d'intégrité. Cela permet de télécharger l'application Web de manière sécurisée dans son intégralité, et même de la partager ou de l'installer hors connexion.

Toutefois, cela pose un problème pour vérifier l'authenticité du code d'un site : les clés TLS nécessitent une connexion Internet pour fonctionner. Au lieu de clés TLS, les IWA sont signées avec une clé qui peut être conservée hors connexion de manière sécurisée. Bonne nouvelle : si vous pouvez rassembler tous vos fichiers de production dans un dossier, vous pouvez le transformer en IWA sans trop de modifications.

Générer des clés de signature

Les clés de signature sont des paires de clés Ed25519 ou ECDSA P-256, la clé privée étant utilisée pour signer le bundle et la clé publique pour le valider. Vous pouvez utiliser OpenSSL pour générer et chiffrer une clé Ed25519 ou ECDSA P-256 :

# Generate an unencrypted Ed25519 key
openssl genpkey -algorithm Ed25519 -out private_key.pem

# or generate an unencrypted ECDSA P-256 key
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem

# Encrypt the generated key. This will ask for a passphrase, make sure to use a strong one
openssl pkcs8 -in private_key.pem -topk8 -out encrypted_key.pem

# Delete the unencrypted key
rm private_key.pem

Les clés de signature ont également une fonction secondaire. Étant donné qu'un domaine peut être vulnérable à une perte de contrôle comme un serveur, il ne peut pas être utilisé pour identifier l'application Web installée. En revanche, une IWA est identifiée par la clé publique du bundle, qui fait partie de sa signature et est liée à la clé privée. Il s'agit d'un changement important dans le fonctionnement du Web par téléchargement furtif. Ainsi, au lieu d'utiliser HTTPS, les IWA utilisent également un nouveau schéma : isolated-app://.

Regrouper votre application

Maintenant que vous disposez de votre clé de signature, il est temps de regrouper votre application Web. Pour ce faire, vous pouvez utiliser les packages NodeJS officiels pour regrouper, puis signer vos IWA (des outils de ligne de commande Go sont également disponibles). Commencez par utiliser le package wbn en pointant vers le dossier contenant tous les fichiers de production de votre PWA (ici, "dist") pour les regrouper dans un bundle non signé :

npx wbn --dir dist

Cela générera un bundle Web non signé de ce répertoire dans out.wbn.. Une fois généré, utilisez la clé Ed25519 ou ECDSA P-256 chiffrée que vous avez créée précédemment pour le signer à l'aide de wbn-sign :

npx wbn-sign -i out.wbn -k encrypted_key.pem -o signed.swbn

Cela générera un bundle Web signé à partir du bundle Web non signé appelé signed.swbn. Une fois la signature effectuée, l'outil génère également l'ID du bundle Web et l'origine de son appli Web isolée. L'origine de l'application Web isolée permet d'identifier votre AWI dans le navigateur.

Web Bundle ID: ggx2sheak3vpmm7vmjqnjwuzx3xwot3vdayrlgnvbkq2mp5lg4daaaic
Isolated Web App Origin: isolated-app://ggx2sheak3vpmm7vmjqnjwuzx3xwot3vdayrlgnvbkq2mp5lg4daaaic/

Si vous utilisez Webpack, Rollup ou un outil compatible avec leurs plug-ins (comme Vite), vous pouvez utiliser l'un des plug-ins de bundler (Webpack, Rollup) qui encapsule ces packages au lieu de les appeler directement. Cela générera un bundle signé comme résultat de votre compilation.

Tester votre application

Vous pouvez tester votre AWI de deux manières : en exécutant votre serveur de développement via le proxy de développement AWI intégré de Chrome ou en installant votre AWI groupée. Pour ce faire, vous devez utiliser Chrome ou ChromeOS 120 ou version ultérieure, activer les indicateurs d'AWI et installer votre application via les composants internes des applications Web de Chrome :

  1. Activer l'indicateur chrome://flags/#enable-isolated-web-app-dev-mode
  2. Testez votre AWI en accédant à la page "Web App Internals" (Informations internes sur les applications Web) de Chrome à l'adresse chrome://web-app-internals.

Une fois sur la page "Internes de l'application Web", vous avez le choix entre Install IWA with Dev Mode Proxy et Install IWA from Signed Web Bundle.

Si vous installez une application Web installable via un proxy en mode développeur, vous pouvez installer n'importe quelle URL, y compris les sites exécutés à partir d'un serveur de développement local, en tant qu'application Web installable, sans les regrouper, à condition qu'elles répondent aux autres exigences d'installation des applications Web installables. Une fois installé, un IWA pour cette URL sera ajouté à votre système avec les règles de sécurité et les restrictions appropriées, ainsi que l'accès aux API réservées aux IWA. Un identifiant aléatoire lui sera attribué. Les outils pour les développeurs Chrome sont également disponibles dans ce mode pour vous aider à déboguer votre application. Si vous installez une IWA à partir d'un Signed Web Bundle, vous importez votre IWA signée et groupée, et elle s'installe comme si elle avait été téléchargée par un utilisateur final.

Sur la page "Web App Internals" (Internes de l'application Web), vous pouvez également forcer la vérification des mises à jour pour toutes les applications installées via le proxy du mode développeur ou à partir d'un bundle Web signé afin de tester également le processus de mise à jour.

Isolement

La confiance est essentielle pour les applications Web isolées. Cela commence par leur fonctionnement. Les utilisateurs ont des modèles mentaux différents pour ce qu'une application peut et doit faire, selon qu'elle s'exécute dans un navigateur ou dans une fenêtre autonome. Ils pensent généralement que les applications autonomes ont plus d'accès et sont plus puissantes. Étant donné que les IWA peuvent accéder à des API de confiance élevée, elles doivent s'exécuter dans une fenêtre autonome pour s'aligner sur ce modèle mental. Cela les sépare visuellement du navigateur. Mais cela va au-delà de la séparation visuelle.

Les applications Web isolées s'exécutent sur un protocole distinct de celui des sites Web dans le navigateur (isolated-app par rapport à http ou https). Cela signifie que chaque AWI est entièrement séparée des sites Web exécutés dans le navigateur, même s'ils sont développés par la même entreprise, grâce à la politique d'origine identique. Le stockage des IWA est également séparé. Cela permet de s'assurer que le contenu multi-origine ne peut pas fuiter entre différentes AWI ni entre les AWI et le contexte de navigation normal d'un utilisateur.

Toutefois, ni l'isolation, ni l'assemblage et la signature du code d'un site ne sont utiles pour établir la confiance si une PWA peut télécharger et exécuter du code arbitraire après l'installation. Pour garantir cela tout en permettant aux PWA de se connecter à d'autres sites pour obtenir du contenu, les PWA appliquent un ensemble rigoureux de stratégies de sécurité du contenu :

  • n'autorise que le JavaScript du bundle, mais permet l'exécution de Wasm quelle que soit sa source. (script-src)
  • Autorise JavaScript à récupérer des données à partir de domaines sécurisés et non localhost d'origine croisée, à se connecter aux points de terminaison WebSocket et WebTransport, ainsi qu'aux URL blob et data (connect-src)
  • Protège contre les attaques par injection de script intersites (XSS) dans le DOM en réglementant l'utilisation des fonctions de manipulation du DOM (require-trusted-types-for)
  • Autorise les frames, les images, l'audio et les vidéos de n'importe quel domaine HTTPS (frame-src, img-src, media-src)
  • Autorise les polices du bundle et les blobs (font-src)
  • Autoriser le CSS intégré ou le CSS du bundle (style-src)
  • Les éléments <object>, <embed> et <base> ne peuvent pas être utilisés (object-src et base-uri).
  • N'autorise que les ressources du bundle pour toute autre demande couverte par le CSP (default-src)
Content-Security-Policy: script-src 'self' 'wasm-unsafe-eval';
  connect-src 'self' https: wss: blob: data:;
  require-trusted-types-for 'script';
  frame-src 'self' https: blob: data:;
  img-src 'self' https: blob: data:;
  media-src 'self' https: blob: data:;
  font-src 'self' blob: data:;
  style-src 'self' 'unsafe-inline';
  object-src 'none';
  base-uri 'none';
  default-src 'self';

Ces CSP ne suffisent pas à protéger complètement contre le code tiers potentiellement malveillant. Les IWA sont également isolées multi-origines, ce qui définit des en-têtes pour réduire la capacité des ressources tierces à les affecter :

  • N'autorisez que les ressources du bundle ou les ressources à origines multiples explicitement marquées comme compatibles avec CORS, avec un en-tête de stratégie de ressources à origines multiples (CORP) défini ou l'attribut crossorigin. (Cross-Origin-Embedder-Policy)
  • Interdire les requêtes cross-origin sans CORS (Cross-Origin-Resource-Policy)
  • Isoler le contexte de navigation des documents d'origine croisée au niveau du processus, en empêchant les références window.opener et l'accès aux objets globaux (Cross-Origin-Opener-Policy)
  • Empêcher l'intégration du site dans un frame ou un iFrame (CSP, frame-ancestors)
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
Content-Security-Policy: frame-ancestors 'self'

Même avec ces restrictions, il existe une autre attaque potentielle contre laquelle les IWA se protègent : les attaques de rupture de séquence. Une attaque par rupture de séquence se produit lorsqu'un contenu tiers malveillant tente de créer une expérience utilisateur déroutante et potentiellement exploitable en accédant à une page de manière inattendue, par exemple en accédant directement à une page de paramètres internes. Les IWA empêchent cela en interdisant l'association directe arbitraire à partir de sites externes. Elles n'autorisent l'ouverture des applications qu'en accédant à des points d'entrée bien définis, comme un start_url, un gestionnaire de protocole, une cible de partage ou un gestionnaire de lancement.

Verrouillé

L'encapsulation et l'isolation fournissent un ensemble de garanties concernant ce qui est autorisé à s'exécuter et d'où cela provient. Toutefois, la nature dynamique des autorisations sur le Web signifie qu'elles ne peuvent pas, à elles seules, garantir qu'une application Web n'utilise que les fonctionnalités dont elle a besoin. Étant donné que différentes fonctionnalités ont des considérations de sécurité différentes, un utilisateur ou un administrateur souhaitera vérifier les autorisations qu'une AWP peut utiliser, tout comme il peut le faire avec d'autres applications natives telles qu'Android et iOS avant d'installer ou de mettre à jour une application.

Pour ce faire, les applications Web isolées bloquent toutes les demandes d'autorisation par défaut. Les développeurs peuvent ensuite activer l'autorisation dont ils ont besoin en ajoutant un champ permissions_policy à leur fichier manifeste d'application Web. Ce champ contient des paires clé/valeur de directives de stratégie d'autorisation et de listes d'autorisation de stratégie d'autorisation pour chaque autorisation que l'IWA, ou tout frame enfant tel qu'un Controlled Frame ou un iframe, peut demander. L'ajout d'une autorisation ici ne l'accorde pas automatiquement. Il la rend disponible pour être demandée lorsqu'une demande pour cette fonctionnalité est effectuée.

Prenons l'exemple d'une IWA de suivi de flotte. Votre PWA peut avoir besoin de demander la position de l'utilisateur, et une carte intégrée peut également demander la position. Vous pouvez également souhaiter que tout site intégré puisse passer en plein écran pour offrir une vue immersive à l'utilisateur. Pour ce faire, vous devez configurer la règle d'autorisation suivante dans le fichier manifeste de votre application Web :

"permissions_policy": {
   "geolocation": [ "self", "https://map.example.com" ],
   "fullscreen": [ "*" ]
}

Étant donné que les WebBundles peuvent également spécifier des en-têtes Permissions-Policy, seules les autorisations déclarées dans les deux seront autorisées, et seules les origines des listes d'autorisation qui se trouvent dans les deux seront autorisées.

Nommée et versionnée

Les applications Web normales s'appuient sur leur nom de domaine pour s'identifier auprès des utilisateurs. Elles peuvent être mises à jour en modifiant le code diffusé sur ce domaine. Toutefois, en raison des contraintes de sécurité liées aux applications Web isolées, l'identité et les mises à jour doivent être gérées différemment. Comme les applications Web progressives, les applications Web isolées ont besoin d'un fichier manifeste d'application Web pour être identifiées par vos utilisateurs.

Fichier manifeste d'application Web

Les applications Web isolées partagent les mêmes propriétés clés du fichier manifeste pour leur fichier manifeste d'application Web que les PWA, avec quelques légères variations. Par exemple, display fonctionne un peu différemment : browser et minimal-ui sont forcés dans un affichage minimal-ui, et fullscreen et standalone sont forcés dans un affichage standalone (les options display_override supplémentaires fonctionnent comme prévu). De plus, deux autres champs doivent être inclus : version et update_manifest_url :

  • version : obligatoire pour les applications Web isolées. Chaîne composée d'un ou de plusieurs entiers séparés par un point (.). Votre version peut être simple (1, 2, 3, etc.) ou complexe (SemVer, 1.2.3). Le numéro de version doit correspondre à l'expression régulière ^(\d+.?)*\d$.
  • update_manifest_url : champ facultatif, mais recommandé, qui pointe vers une URL HTTPS (ou localhost pour les tests) où un fichier manifeste de mise à jour d'application Web peut être récupéré.

Voici un exemple de fichier manifeste d'application Web minimal pour une application Web isolée :

{
  "name": "IWA Kitchen Sink",
  "version": "0.1.0",
  "update_manifest_url": "https://example.com/updates.json",
  "start_url": "/",
  "icons": [
    {
      "src": "/images/icon.png",
      "type": "image/png",
      "sizes": "512x512",
      "purpose": "any"
    },
    {
      "src": "/images/icon-mask.png",
      "type": "image/png",
      "sizes": "512x512",
      "purpose": "maskable"
    }
  ]
}

Fichier manifeste de mise à jour d'application Web

Un fichier manifeste de mise à jour d'application Web est un fichier JSON qui décrit chaque version d'une application Web donnée. L'objet JSON contient un champ obligatoire, version, qui est une liste d'objets contenant version, src et channels :

  • version : numéro de version de l'application, identique au champ version du fichier manifeste de l'application Web
  • src : URL HTTPS (ou localhost pour les tests) pointant vers le bundle hébergé pour cette version (fichier .swbn). Les URL relatives sont relatives au fichier manifeste de mise à jour de l'application Web.
  • channels : liste de chaînes permettant d'identifier le canal de mise à jour auquel appartient cette version. Un canal default spécial est utilisé pour décrire le canal principal qui sera utilisé si aucun autre canal n'est sélectionné.

Vous pouvez également inclure un champ channels, un objet de vos ID de chaîne avec une propriété name facultative pour chaque ID afin de fournir un nom lisible par l'utilisateur (y compris pour la chaîne default). Une chaîne qui n'inclut pas la propriété name ou qui n'est pas incluse dans l'objet channels utilise son ID comme nom.

Voici à quoi pourrait ressembler un fichier manifeste de mise à jour minimal :

{
  "versions": [
    {
      "version": "5.2.17",
      "src": "https://cdn.example.com/app-package-5.2.17.swbn",
      "channels": ["next", "5-lts", "default"]
    },
    {
      "version": "5.3.0",
      "src": "v5.3.0/package.swbn",
      "channels": ["next", "default"]
    },
    {
      "version": "5.3.1",
      "src": "v5.3.1/package.swbn",
      "channels": ["next"]
    },
  ],
  "channels": {
    "default": {
      "name": "Stable"
    },
    "5-lts": {
      "name": "5.x Long-term Stable"
    }
  }
}

Dans cet exemple, il existe trois canaux : default qui sera libellé Stable, 5-lts qui sera libellé 5.x Long-term Stable et next qui sera libellé next. Si un utilisateur se trouve sur le canal 5-lts, il obtient la version 5.2.17. S'il se trouve sur le canal default, il obtient la version 5.3.0. S'il se trouve sur le canal next, il obtient la version 5.3.1.

Les fichiers manifestes de mise à jour des applications Web peuvent être hébergés sur n'importe quel serveur. Les mises à jour sont recherchées toutes les quatre à six heures.

Gérée par l'administrateur

Pour leur lancement initial, les applications Web isolées ne pourront être installées que sur les Chromebooks gérés par Chrome Enterprise par un administrateur via la console d'administration.

Pour commencer, dans le panneau d'administration, accédez à Appareils > Chrome > Applications et extensions > Utilisateurs et navigateurs. Cet onglet vous permet d'ajouter des applications et des extensions du Chrome Web Store, de Google Play et du Web pour les utilisateurs de votre organisation. Pour ajouter des éléments, ouvrez le bouton jaune flottant Ajouter + en bas à droite de l'écran, puis sélectionnez le type d'élément à ajouter.

Une fois ouvert, un carré s'affiche à l'intérieur d'un autre carré, avec le libellé Ajouter une application Web isolée. Cliquez dessus pour ouvrir une fenêtre modale permettant d'ajouter une AWI à votre UO. Pour ce faire, vous aurez besoin de deux informations : l'ID de bundle Web de l'AWI (généré à partir de la clé publique de votre application et affiché une fois l'application groupée et signée) et l'URL du fichier manifeste de mise à jour de l'application Web pour l'AWI. Une fois installé, vous disposerez de l'ensemble standard d'options du panneau d'administration pour le gérer :

  • Règles d'installation : indiquez comment vous souhaitez que l'application Web installable soit installée (d'office, d'office et épinglée à l'étagère ChromeOS, ou non installée).
  • Lancer à la connexion : indiquez comment vous souhaitez que l'application Web installée soit lancée. Vous pouvez autoriser l'utilisateur à la lancer manuellement, forcer le lancement de l'application Web installée lorsque l'utilisateur se connecte, mais lui permettre de la fermer, ou forcer le lancement lorsque l'utilisateur se connecte et l'empêcher de la fermer.

Une fois l'application enregistrée, elle sera installée la prochaine fois qu'une mise à jour des règles sera appliquée aux Chromebooks de cette UO. Une fois installée, l'appareil d'un utilisateur recherche les mises à jour du fichier manifeste de mise à jour de l'application Web toutes les quatre à six heures.

En plus d'installer de force les AWI, vous pouvez également leur accorder automatiquement certaines autorisations, comme vous le faites pour les autres applications Web. Pour ce faire, accédez à Appareils > Chrome > Fonctionnalités Web, puis cliquez sur le bouton Ajouter une origine. Dans Origin / site pattern field, collez l'ID du bundle Web de l'AWI (isolated-app:// sera automatiquement ajouté en tant que protocole). Vous pouvez ensuite définir des niveaux d'accès à différentes API (autorisé/bloqué/non défini), y compris la gestion des fenêtres, la gestion des polices locales et l'API de surveillance de l'écran. Pour les API qui peuvent nécessiter une activation supplémentaire par un administrateur, comme l'API de surveillance d'écran obligatoire, une boîte de dialogue supplémentaire s'affiche pour confirmer votre sélection. Une fois les modifications terminées, enregistrez-les. Vos utilisateurs pourront alors commencer à utiliser votre PWA.

Utiliser les extensions

Bien que les applications Web isolées ne fonctionnent pas avec les extensions prêtes à l'emploi, vous pouvez y associer les extensions dont vous êtes propriétaire. Pour ce faire, vous devez modifier le fichier manifeste de l'extension. La section externally_connectable du fichier manifeste définit les pages Web externes ou les autres extensions Chrome avec lesquelles votre extension peut interagir. Ajoutez l'origine de votre AWP dans le champ matches de externally_connectable (veillez à inclure le schéma isolated-app://) :

{
  "externally_connectable": {
    "matches": ["isolated-app://79990854-bc9f-4319-a6f3-47686e54ed29/*"]
  }
}

Cela permettra à votre extension de s'exécuter dans l'application Web isolée, mais pas d'y injecter du contenu. Vous êtes limité à transmettre des messages entre l'extension et votre AWI.