Navigateur, messagerie et synchronisation cloud · Leçon 2 sur 6
Firefox : places.sqlite et données de session
12 min de lecture
Firefox conserve son historique dans son propre schéma SQLite, ses propres fichiers JSON et un format de session compressé, avec des horodatages calculés à partir d'une époque différente de celle de Chromium. Cette leçon présente l'emplacement d'un profil Firefox, les tables qui permettent de déterminer « ce qui a été consulté, saisi et téléchargé, et à quel moment », ainsi que la manière d'ouvrir les fichiers de session qui enregistrent les onglets ouverts et récemment fermés. La leçon 4.3 traite du cache et de la navigation privée.
Localisation du profil
Sous Windows, chaque profil possède deux dossiers de même nom : %APPDATA%\Mozilla\Firefox\Profiles\<random>.<name> (itinérant : les bases de données et les fichiers JSON de cette leçon) et %LOCALAPPDATA%\Mozilla\Firefox\Profiles\<random>.<name> (local : le cache). Le préfixe comporte huit caractères aléatoires ; les versions actuelles nomment le profil créé pour chaque installation default-release, par exemple k3x9p2qa.default-release.
Deux fichiers dans %APPDATA%\Mozilla\Firefox\ indiquent quel profil était utilisé. profiles.ini répertorie chaque profil dans une section [ProfileN] (Name, IsRelative, Path) et, depuis Firefox 67, contient une section [Install<hash>] dont la ligne Default= désigne le profil utilisé par une installation. installs.ini reprend cette correspondance, avec une section par empreinte d'installation. Un profil nommé default avec Default=1 est souvent un ancien profil presque vide : suivez donc l'entrée [Install…], tout en examinant chaque dossier de profil présent.
Sous Linux, les profils se trouvent dans ~/.mozilla/firefox/, et le cache dans ~/.cache/mozilla/firefox/. Le paquet Snap utilise ~/snap/firefox/common/.mozilla/firefox/ et le paquet Flatpak ~/.var/app/org.mozilla.firefox/.mozilla/firefox/. À partir de Firefox 147, les nouvelles installations suivent l'organisation XDG dans ~/.config/mozilla/firefox/. Recherchez tous les fichiers profiles.ini plutôt que de vous fier à un seul chemin.
La plupart des bases de données Firefox fonctionnent en mode de journalisation anticipée (WAL). Collectez places.sqlite avec places.sqlite-wal et places.sqlite-shm (de même pour les cookies, l'historique des formulaires et les favicons) : les visites récentes peuvent n'exister que dans le WAL. Calculez les empreintes de l'ensemble, puis travaillez sur des copies, car l'ouverture d'une base de données avec SQLite peut déclencher un point de contrôle qui intègre le WAL au fichier principal et modifie les deux.
places.sqlite
moz_places et moz_historyvisits
moz_places contient une ligne par URL : url, title, rev_host (le nom d'hôte inversé caractère par caractère, suivi d'un point, de sorte que transfer.example.com devient moc.elpmaxe.refsnart.), visit_count, typed (1 si l'URL a déjà été saisie), frecency (un score de classement pour les suggestions de la barre d'adresse, et non une date), last_visit_date et guid. moz_historyvisits contient une ligne par visite : place_id (jointure avec moz_places.id), visit_date, visit_type et from_visit (l'id de la visite qui a mené à celle-ci, ou 0 en l'absence de visite précédente). Les deux dates sont au format PRTime : des microsecondes depuis le 1970-01-01 UTC (leçon 3.1).
| visit_type | Nom | Signification |
|---|---|---|
| 1 | LINK | Lien suivi |
| 2 | TYPED | Adresse saisie ou sélectionnée dans la barre d'adresse |
| 3 | BOOKMARK | Page ouverte depuis un marque-page |
| 4 | EMBED | Contenu intégré ; les versions actuelles conservent ces visites en mémoire, elles sont donc rarement présentes sur disque |
| 5 | REDIRECT_PERMANENT | Page atteinte par une redirection permanente, telle que HTTP 301 |
| 6 | REDIRECT_TEMPORARY | Page atteinte par une redirection temporaire, telle que HTTP 302 |
| 7 | DOWNLOAD | URL récupérée dans le cadre d'un téléchargement |
| 8 | FRAMED_LINK | Lien suivi à l'intérieur d'un cadre |
| 9 | RELOAD | Page rechargée |
Remonter les valeurs de from_visit permet de reconstituer une chaîne de navigation. Firefox supprime automatiquement les anciennes entrées de l'historique : l'absence d'une visite ne prouve donc pas qu'elle n'a pas eu lieu.
Marque-pages, saisies et origines
moz_bookmarks stocke les marque-pages (type 1), les dossiers (2) et les séparateurs (3), avec fk pointant vers moz_places.id, parent, title, ainsi que dateAdded et lastModified au format PRTime. moz_inputhistory enregistre ce que l'utilisateur a saisi dans la barre d'adresse et le résultat qu'il a ensuite choisi : input (le texte saisi), place_id (la page sélectionnée) et use_count, un score décroissant. Cette table ne contient aucun horodatage ; datez donc ces saisies à l'aide des visites correspondantes. moz_origins conserve une ligne par combinaison schéma-hôte (prefix, host, frecency), référencée par moz_places.origin_id.
Téléchargements
Depuis Firefox 26, les téléchargements sont enregistrés dans places.sqlite ; les anciens profils utilisaient un fichier downloads.sqlite distinct. Un téléchargement ajoute une visite de type 7 pour l'URL source et deux annotations de page dans moz_annos, rattachées au place_id de cette URL et nommées par l'intermédiaire de moz_anno_attributes.name :
downloads/destinationFileURI:contentcontient l'emplacement d'enregistrement sous forme d'URI, par exemplefile:///C:/Users/jsilva/Downloads/Q1_payroll.zip.downloads/metaData:contentcontient du JSON avecstate(1 terminé, 2 échoué, 3 annulé ; d'autres valeurs indiquent des téléchargements en pause ou bloqués),endTimeen millisecondes depuis 1970 UTC,fileSize(présent lorsque le téléchargement a réussi) etdeleted.
Les lignes de moz_annos comportent également dateAdded et lastModified au format PRTime. Corroborez ces informations avec le système de fichiers : l'entrée $MFT du fichier et son flux Zone.Identifier (leçon 1.4).
Autres fichiers du profil
favicons.sqlite: icônes (moz_icons) liées aux URL des pages (moz_pages_w_icons), une trace corroborant le chargement d'une page ou son ajout aux marque-pages.formhistory.sqlite:moz_formhistorystocke les valeurs saisies dans les champs des formulaires web :fieldname,value,timesUsed,firstUsedetlastUsed(PRTime). Les champs de recherche y figurent également, souvent avec la valeursearchbar-historypourfieldname.cookies.sqlite:moz_cookiesavechost,name,value,creationTimeetlastAccessed(PRTime), ainsi queexpiry. Les valeurs ne sont pas chiffrées. Les anciennes versions stockentexpiryen secondes Unix et les versions actuelles en millisecondes ; vérifiez donc le nombre de chiffres.permissions.sqlite:moz_permsenregistre les autorisations des sites (origin,type, tel quedesktop-notificationoucamera,permission,modificationTime).logins.json: identifiants de connexion enregistrés.hostname,formSubmitURLet les horodatages sont lisibles ;encryptedUsernameetencryptedPasswordsont chiffrés avec une clé conservée danskey4.db(base de données de clés NSS, au format SQLite depuis Firefox 58), protégée par le mot de passe principal si celui-ci est défini.extensions.json: modules complémentaires installés avecid,version,active,installDateetupdateDate(millisecondes), ainsi quepath; les paquets se trouvent dansextensions\sous forme de fichiers.xpi.addons.jsonmet en cache les métadonnées de la boutique de modules complémentaires. Recherchez les modules complémentaires que l'utilisateur n'aurait pas installés en connaissance de cause.
Données de session
Le dossier sessionstore-backups contient l'état de la session :
recovery.jsonlz4: la session en cours, réécrite pendant l'exécution de Firefox (toutes les 15 secondes par défaut).recovery.baklz4: la copie précédente du fichier de récupération.previous.jsonlz4: la session antérieure au dernier redémarrage.upgrade.jsonlz4-<buildID>: une copie créée lors de la mise à jour de Firefox, nommée à l'aide de l'identifiant de compilation à 14 chiffres.- Lors d'un arrêt normal, Firefox écrit également
sessionstore.jsonlz4à la racine du profil.
Les fichiers utilisent le conteneur LZ4 propre à Mozilla : les octets 0–7 correspondent à la signature mozLz40\0 (6D 6F 7A 4C 7A 34 30 00), les octets 8–11 à la taille décompressée sous forme d'entier 32 bits en petit-boutiste, et le reste à un unique bloc LZ4 brut, et non à une trame LZ4 ; l'outil standard en ligne de commande lz4 le rejette donc. Utilisez un outil dédié tel que dejsonlz4 ou lz4json, ou Python : lz4.block.decompress(data[12:], uncompressed_size=int.from_bytes(data[8:12], 'little')). De manière équivalente, utilisez lz4.block.decompress(data[8:]), car cette fonction lit par défaut un préfixe de taille de 4 octets en petit-boutiste.
Le JSON révèle windows[].tabs[], chacun avec entries[] (l'historique de navigation précédent et suivant de l'onglet : url, title, référent), un index indiquant l'entrée actuelle et lastAccessed ; _closedTabs avec closedAt ; _closedWindows ; ainsi que formdata, qui contient le texte saisi dans les champs des pages (les champs de mot de passe ne sont pas enregistrés). Les horodatages de session sont en millisecondes depuis 1970 UTC. La comparaison de previous.jsonlz4 avec recovery.jsonlz4 montre ce qui a changé entre les sessions.
Firefox et Chromium côte à côte
| Fichier Firefox | Équivalent Chromium | Informations fournies |
|---|---|---|
places.sqlite : moz_places, moz_historyvisits | History : urls, visits | Quelles pages ont été consultées, quand et comment elles ont été atteintes |
places.sqlite : moz_annos | History : downloads, downloads_url_chains | Ce qui a été téléchargé, depuis quelle source et vers quel emplacement |
places.sqlite : moz_inputhistory | Shortcuts : omni_box_shortcuts | Ce que l'utilisateur a saisi dans la barre d'adresse |
places.sqlite : moz_bookmarks | Bookmarks (JSON) | Pages enregistrées délibérément et moment de leur enregistrement |
formhistory.sqlite | Web Data : autofill | Valeurs saisies dans les formulaires web |
cookies.sqlite | Network\Cookies (valeurs chiffrées) | Sites consultés et sessions conservées |
logins.json + key4.db | Login Data + clé de Local State | Identifiants de connexion enregistrés et sites associés |
sessionstore-backups\*.jsonlz4 | Sessions\Session_*, Tabs_* | Onglets ouverts et fermés, données des formulaires des pages |
extensions.json | Extensions\ + Preferences | Modules complémentaires installés |
Exemple détaillé : saisie, puis téléchargement
Une collecte de triage contient places.sqlite et son WAL. La question : l'utilisateur s'est-il rendu délibérément sur un site de transfert de fichiers, et quand un téléchargement s'est-il terminé ? Exécutez :
SELECT v.id, v.from_visit, strftime('%Y-%m-%dT%H:%M:%SZ', v.visit_date/1000000, 'unixepoch') AS visit_utc, v.visit_type, p.url FROM moz_historyvisits v JOIN moz_places p ON p.id = v.place_id ORDER BY v.visit_date;
| id | from_visit | visit_utc | visit_type | url |
|---|---|---|---|---|
| 1201 | 0 | 2026-05-19T08:41:37Z | 2 | https://transfer.example.com/ |
| 1202 | 1201 | 2026-05-19T08:42:18Z | 1 | https://transfer.example.com/d/7Hq2 |
| 1203 | 1202 | 2026-05-19T08:42:25Z | 7 | https://dl.transfer.example.com/7Hq2/Q1_payroll.zip |
La valeur brute de visit_date pour la visite 1201 est 1 779 180 097 512 334. La division entière par 1 000 000 donne 1 779 180 097 secondes, soit 2026-05-19T08:41:37Z ; la division tronque les 0,512334 s, comme il convient pour une réponse en secondes entières. (datetime(visit_date/1000000,'unixepoch') donne le même instant sans le T et le Z.) La visite 1201 est de type TYPED sans référent, et moz_inputhistory contient input = trans pointant vers cette page : l'utilisateur a donc saisi le début de l'adresse. La visite 1202 correspond à un lien suivi depuis 1201, et la visite 1203 à un téléchargement lancé depuis 1202.
Pour l'entrée correspondant à l'URL du ZIP (la cible de la visite 1203), downloads/metaData contient {"state":1,"deleted":false,"endTime":1779180163904,"fileSize":48213977}. Ici, endTime est en millisecondes : 1 779 180 163 904 ÷ 1 000 = 1 779 180 163,904 s ; le téléchargement s'est donc terminé à 2026-05-19T08:42:43Z, soit 18 secondes après la visite de type 7.
Ne confondez pas les époques des navigateurs. Chromium stocke le même instant en microsecondes depuis 1601 : (1 779 180 097 + 11 644 473 600) × 1 000 000 + 512 334 = 13 423 653 697 512 334, et la requête Chromium doit soustraire 11 644 473 600 après la division. Si vous décodez la valeur Firefox avec la formule de Chromium, vous obtenez 1657-05-19T08:41:37Z ; si vous décodez la valeur Chromium comme du PRTime, vous obtenez 2395-05-19T08:41:37Z. Les deux unités sont des microsecondes : seule l'époque les distingue ; en 2026, une valeur à 16 chiffres correspond à PRTime et une valeur à 17 chiffres à l'heure Chromium.
Outils
DB Browser for SQLite exécute des requêtes comme celle présentée ci-dessus. Plaso dispose de greffons SQLite pour Firefox, tels que firefox_history, firefox_downloads et firefox_10_cookies ; comparez leurs résultats avec ceux d'une requête manuelle, car les schémas changent d'une version à l'autre (par exemple, Plaso lit expiry des cookies comme des secondes, alors que Firefox 142 et les versions ultérieures stockent des millisecondes). Hindsight analyse uniquement les navigateurs fondés sur Chromium et ne lit pas les profils Firefox.
Points clés pour l'examen : Attendez-vous à convertir des valeurs PRTime en ISO 8601 UTC, à interpréter les codesvisit_type(en particulier 2 TYPED et 7 DOWNLOAD) et à récupérer le chemin d'enregistrement et l'heure de fin d'un téléchargement à partir demoz_annos, en gardant à l'esprit queendTimeest en millisecondes. Vous devrez peut-être aussi localiser le profil actif à partir deprofiles.iniou deinstalls.ini, ou reconnaître l'en-têtemozLz40\0et sa longueur de 12 octets.
Points essentiels
- Le profil itinérant contient les bases de données et le profil local contient le cache ;
profiles.inietinstalls.iniidentifient le profil utilisé par chaque installation. - Joignez
moz_historyvisits.place_idàmoz_places.id; PRTime correspond aux microsecondes depuis 1970 UTC, tandis que l'heure Chromium correspond aux microsecondes depuis 1601. - Depuis Firefox 26, les téléchargements correspondent à une visite de type 7 accompagnée des annotations
downloads/destinationFileURIetdownloads/metaData, avecendTimeen millisecondes. - L'historique des formulaires, les valeurs des cookies et les données de formulaire de la session sont stockés sans chiffrement ; les mots de passe enregistrés nécessitent
key4.db. - Les fichiers de session se composent d'un en-tête
mozLz40\0de 12 octets suivi d'un bloc LZ4, et révèlent les onglets ouverts, les onglets fermés et les données saisies dans les formulaires. - Collectez toujours les fichiers
-walet-shmet analysez des copies.