browserforensics
Retour à tous les articles

Local Storage et IndexedDB de Chrome (LevelDB)

2026-05-19 · 3 min

Au-delà des fichiers SQLite, Chrome conserve l'état des applications web dans des magasins clé-valeur LevelDB. La plupart des enquêteurs les sautent et passent à côté de la source la plus riche en preuves d'intention sur la machine. Une identité connectée, un brouillon de message, un jeton OAuth, l'URL d'un document Drive que l'utilisateur a ouvert : ces données résident dans Local Storage ou IndexedDB, pas dans History.

Où c'est stocké dans le profil

Local Storage/leveldb/             # window.localStorage par origine
Session Storage/                   # session storage par onglet
IndexedDB/<origin>.indexeddb.leveldb/    # bases applicatives structurées
IndexedDB/<origin>.indexeddb.blob/        # gros blobs référencés par le LDB

Chaque entrée est un dossier, pas un fichier unique : CURRENT, MANIFEST-NNNNNN, un ou plusieurs SSTables *.ldb, et un write-ahead log *.log. Copiez tout le répertoire ou LevelDB refusera de l'ouvrir.

Le format qu'il faut réellement lire

LevelDB est un arbre LSM. Pour énumérer correctement les clés :

  1. Lisez CURRENT pour trouver le manifest actif.
  2. Parcourez MANIFEST-* pour savoir quels SSTables sont actifs et à quel niveau.
  3. Fusionnez les SSTables actifs avec le WAL *.log ; le dernier écrit l'emporte par clé.
  4. Pour chaque bloc, décompressez Snappy si le trailer l'indique.

Les valeurs nécessitent ensuite un décodage spécifique au format :

  • Les clés Local Storage sont _<origin>\x00<key>. Les valeurs commencent par un marqueur d'encodage d'un octet : 0x00 UTF-16LE, 0x01 Latin-1, parfois précédé d'un octet meta.
  • Session Storage utilise une indirection namespace -> map -> key. Résolvez via les clés de meta-namespace avant d'extraire les valeurs.
  • Les valeurs IndexedDB sont encodées en V8 structured-clone. Nombres, chaînes et objets simples se relèvent proprement ; les références cycliques et les typed arrays demandent une gestion attentive.

Les vraies preuves que l'on trouve ici

  • Slack, Teams, Discord, Notion : ID utilisateur connecté, ID d'espace de travail, canaux récemment ouverts, brouillons de messages.
  • Google Docs / Drive : ID de fichier (la longue partie aléatoire d'une URL Drive), titres des documents récemment modifiés, état de synchronisation.
  • VS Code Web / GitHub Codespaces : chemins de fichiers ouverts, noms de dépôts.
  • Banque et SSO : jetons JWT avec des revendications encore exploitables (audience, émetteur, expiration, parfois le nom d'utilisateur).
  • Portefeuilles crypto : adresses stockées, souvent l'identifiant du portefeuille.

Mises en garde

  • Le WAL (*.log) contient les écritures les plus récentes. Si vous ne copiez que les fichiers *.ldb, vous perdez les dernières minutes d'activité.
  • La compaction LevelDB peut produire des tombstones pour les clés supprimées qui ressortent malgré tout pendant la fusion. Traitez les NUL inexpliqués dans votre sortie comme des suppressions, pas comme des données.
  • Les navigateurs migrent parfois les origines entre magasins LevelDB. Un arrêt propre est plus tolérant ; un plantage en cours de migration peut laisser des données orphelines qui méritent d'être récupérées manuellement.

Pour aller plus loin