Guide — la vérification des listes de blocage dans Navkrypt
Ce guide explique comment Navkrypt s'assure qu'une liste de blocage est authentique avant de s'en servir, comment le voir depuis le navigateur, comment le vérifier soi-même sans nous croire sur parole, et ce que veut dire chaque refus. Il s'adresse à trois lecteurs :
- l'utilisateur qui veut savoir si ses listes sont vérifiées (§ 2 et § 3) ;
- l'auditeur qui veut le contrôler lui-même, commandes à l'appui (§ 5) ;
- l'opérateur du miroir qui publie les listes (§ 4 et § 6).
Ce guide est tenu à jour par un test (
tests/guide-verification-listes.test.mjs) : chaque motif de refus, chaque seuil, le texte exact des messages et chaque commande cités ici sont confrontés au code. Le parcours du § 5.1 est exécuté par ce test. Un guide qui dirait autre chose que le code fait tomber la CI.
1. Le problème, en une phrase
uBlock Origin (uBO), le bloqueur intégré à Navkrypt, télécharge d'origine ses listes (EasyList, EasyPrivacy, listes uBO, URLhaus, Peter Lowe…) en HTTPS sans aucune signature : HTTPS dit « ce fichier vient bien de ce serveur », pas « ce fichier est celui que l'éditeur a publié ». Un CDN compromis, un serveur détourné ou une liste vidée par erreur passeraient sans un mot.
Navkrypt ajoute deux verrous indépendants :
| Verrou | Où | Ce qu'il garantit |
|---|---|---|
| La porte de publication | sur le miroir EU (tools/blocklist-mirror.mjs) | aucune liste n'est mise en ligne sans avoir été vérifiée, et le verdict est journalisé avant la mise en ligne |
| La signature | dans le navigateur (patch d'uBO, hardening/ubo-patch/) | uBO refuse toute liste du miroir dont la signature ne se vérifie pas, et affiche un message de confirmation quand elle se vérifie |
Le premier empêche de publier une mauvaise liste ; le second empêche le navigateur d'accepter une liste que la porte n'a pas publiée.
2. Le chemin d'une liste, de l'éditeur à votre navigateur
éditeur (EasyList, uBO…)
│ HTTPS seulement (une redirection hors HTTPS est refusée)
▼
[fetch] téléchargement dans un cache, empreinte SHA-256 relevée
▼
[publish] VÉRIFICATION ─► verdict écrit au journal ─► si ok : SIGNATURE + mise en ligne atomique
│ sinon : refus, l'ancienne copie reste en ligne
▼
[audit] chaque fichier en ligne a-t-il été vérifié AVANT d'être publié ?
▼
[report] rapport du jour : fichiers vérifiés, rejetés, anomalies
▼
miroir EU /lists/<liste>.txt + /lists/<liste>.txt.sig
▼
uBO patché dans Navkrypt : télécharge la liste ET sa signature, vérifie, puis confirme ou refuse
Les cinq étapes côté miroir tournent une fois par jour (tâche planifiée navkrypt-blocklist-mirror.timer, 04:30 UTC) : fetch, puis daily qui enchaîne publish, audit et report.
3. Côté navigateur : voir la vérification
3.1 Où lire le message
Chaque fois qu'uBO charge ou met à jour une liste venue du miroir Navkrypt, il écrit un message :
- dans le journal d'uBO (icône uBO → *Ouvrir le journal*, les messages apparaissent comme des lignes
info/error) ; - dans la console de dépannage d'uBO (Tableau de bord → onglet *Support*).
3.2 Le message de confirmation
Une liste dont la signature est vérifiée produit exactement :
Navkrypt : signature de la liste vérifiée — <chemin> (clé <kid>, signée le <date>)
par exemple Navkrypt : signature de la liste vérifiée — /lists/easylist.txt (clé nk-listes-1, signée le 2026-10-06T04:30:12.345Z). Le message apparaît une fois par téléchargement.
3.3 Le message de refus
Une liste refusée produit exactement :
Navkrypt : liste REFUSÉE — signature <motif> — <chemin>
Ce qui se passe alors : le contenu reçu est jeté, uBO traite le téléchargement comme raté, et la copie déjà en cache reste en service. Vous gardez la protection d'hier ; vous ne recevez pas une liste dont on ne peut pas prouver l'origine.
Attention : Défaut d'uBO d'origine (1.75.0), pas de Navkrypt : après un téléchargement raté, son programme de mise à jour écrit quand même
Full updater: successfully updated <liste>. Rien n'a été écrit en cache. La ligneNavkrypt : liste REFUSÉE …qui précède est la vraie.
3.4 Motifs de refus dans le navigateur
Les contrôles sont faits dans cet ordre ; le premier qui échoue donne le motif.
| Motif | Ce que ça veut dire | Que faire |
|---|---|---|
absente | le serveur n'a pas fourni de fichier .sig à côté de la liste | rien côté utilisateur : la copie en cache reste ; côté miroir, la liste a été publiée sans --key |
illisible | la signature n'est pas du JSON, ou dépasse 4 096 octets | signaler : fichier corrompu ou fabriqué |
format | JSON valide mais pas une signature Navkrypt (champ manquant, mauvaise version, date illisible) | signaler |
cle-inconnue | signée par une clé que ce navigateur ne connaît pas | normal si aucune clé n'est encore livrée (voir § 7) ; sinon : signature d'un tiers, à signaler |
invalide | la signature cryptographique (ECDSA P-256) ne correspond pas | sérieux : quelqu'un a fabriqué ou altéré la signature |
chemin | signature authentique, mais d'une autre liste | sérieux : tentative de substituer une liste à une autre |
empreinte | signature authentique de cette liste, mais le contenu reçu a changé | sérieux : la liste a été modifiée après signature |
date-future | signée plus de 10 minutes dans le futur | vérifier l'horloge de l'ordinateur |
perimee | signature plus vieille que 30 jours | le miroir ne se met plus à jour : une vieille liste ne peut pas être rejouée indéfiniment |
Ce que la signature couvre, et pourquoi : le chemin servi (une liste signée ne peut pas en remplacer une autre), l'empreinte SHA-256 du contenu (aucune ligne ne peut être ajoutée ou retirée), la date de signature (une vieille liste ne peut pas être rejouée). La clé publique de confiance est embarquée dans le navigateur : une liste n'apporte jamais sa propre clé.
3.5 Ce que la signature ne couvre pas
- Les listes que vous ajoutez vous-même depuis une autre adresse que le miroir : uBO les traite comme d'origine, sans message Navkrypt. On ne prétend pas vérifier ce qu'on ne publie pas.
- Les correctifs différentiels d'uBO (
Diff-Path) ne sont pas signés : pour les listes du miroir, le patch les coupe, et la liste se met à jour en entier.
4. Côté miroir : la porte de publication
4.1 Les contrôles avant toute mise en ligne
Pour chaque liste, dans cet ordre, publish refuse la liste au premier contrôle qui échoue :
| Statut | Ce qui a été constaté |
|---|---|
absente | liste non téléchargée, absente du cache, ou sans aucun filtre |
empreinte | le fichier du cache n'a plus l'empreinte relevée au téléchargement : il a été modifié entre les deux |
html | une page HTML (portail captif, page d'erreur) à la place d'une liste |
suspecte | la liste a fondu de plus de 50 % par rapport à la copie actuellement en ligne |
date-inconnue | aucune date de publication dans l'en-tête de la liste |
perimee | publiée par l'éditeur il y a plus de 7 jours, ou plus de 3 fois sa période d'expiration si celle-ci est plus longue |
Une liste refusée n'est pas publiée : la copie précédente reste en ligne, et le passage sort en code 1 (alerte).
4.2 L'ordre qui fait la preuve
- vérifier ;
- écrire le verdict au journal
<servi>/verification.log(une ligne JSON, ajout seul) — avant toute écriture dans le répertoire servi. Si le journal ne peut pas être écrit, rien n'est publié ; - seulement si le verdict est
ok: signer (<f>.sig), déposer la liste parrenameatomique, mettre à jour le manifeste, journaliser la mise en ligne.
C'est cet ordre qui permet à un tiers de contrôler, après coup, qu'aucune liste n'a été mise en ligne sans vérification (§ 5.2).
4.3 Le rapport quotidien
report (lancé chaque jour par daily) tire du journal seul le fichier <servi>/rapports/rapport-AAAA-MM-JJ.txt, en trois parties :
- FICHIERS VERIFIES PUIS MIS EN LIGNE — heure, chemin, empreinte, nombre de filtres, clé de signature (ou
NON SIGNE, dit en clair) ; - FICHIERS REJETES — avec leur statut (§ 4.1) et la source ;
- ANOMALIES — une liste attendue jamais vérifiée ce jour, une vérification
okjamais suivie de sa mise en ligne, aucun passage, une ligne de journal illisible.
Exemple réel : deploy/blocklist-mirror/rapport-2026-10-06-M3.txt (16 vérifiés, 2 rejetés dont easylist amputée de 70 % ⇒ suspecte, et easyprivacy modifiée après téléchargement ⇒ empreinte).
4.4 Codes de sortie
| Commande | 0 | 1 |
|---|---|---|
publish | toutes les listes publiées | au moins une refusée (la précédente reste) |
audit | chaque liste en ligne vérifiée avant publication | sinon, ou miroir vide |
report | un passage, rien de rejeté, aucune anomalie | sinon |
daily | le pire des trois — le rapport est toujours écrit |
Un code non nul met l'unité systemd en failed : c'est l'alerte.
5. Vérifier soi-même (auditeur)
Tout ce qui suit fonctionne avec Node.js ≥ 20 et un clone du dépôt, sans réseau.
5.1 Parcours complet : signer, vérifier, altérer, voir le refus
Ce bloc est exécuté tel quel par tests/guide-verification-listes.test.mjs ; il crée tout dans un dossier temporaire (clé d'essai jetable, jamais la clé de production).
D=$(mktemp -d)
mkdir -p "$D/servi/lists"
printf '! Title: Liste de demonstration\n||traqueur.example^\n' > "$D/servi/lists/demo.txt"
# 1. une clé d'essai : la privée reste dans $D/cle, la publique sert à vérifier
echo "{\"keys\":[$(node tools/ubo-list-signature.mjs keygen essai "$D/cle")]}" > "$D/publiques.json"
# 2. signer la liste comme le fait la porte de publication
node tools/ubo-list-signature.mjs sign --key "$D/cle/essai.private.jwk" --kid essai --root "$D/servi" "$D/servi/lists/demo.txt"
# 3. vérifier : message de confirmation attendu, code 0
node tools/ubo-list-signature.mjs verify --keys "$D/publiques.json" --root "$D/servi" "$D/servi/lists/demo.txt"
# 4. glisser une exception dans la liste, comme le ferait un attaquant
printf '@@||traqueur.example^\n' >> "$D/servi/lists/demo.txt"
# 5. revérifier : refus attendu (motif empreinte), code 1
if node tools/ubo-list-signature.mjs verify --keys "$D/publiques.json" --root "$D/servi" "$D/servi/lists/demo.txt"; then
echo "ANOMALIE : liste alteree acceptee"; exit 1
fi
rm -rf "$D"
Sortie attendue, à l'heure près :
signe /lists/demo.txt (…, essai)
Navkrypt : signature de la liste vérifiée — /lists/demo.txt (clé essai, signée le …)
Navkrypt : liste REFUSÉE — signature empreinte — /lists/demo.txt
verify emploie la même fonction de vérification que le navigateur (le module copié dans uBO, hardening/ubo-patch/navkrypt-list-signature.js) et produit les mêmes messages.
5.2 Contrôler un miroir en service
Sur une copie du répertoire servi (ou sur la machine du miroir) :
# chaque fichier en ligne a-t-il une vérification ok, de la même empreinte, AVANT sa mise en ligne ?
node tools/blocklist-mirror.mjs audit <servi>
# les signatures se vérifient-elles avec les clés publiques du navigateur ?
node tools/ubo-list-signature.mjs verify --keys <publiques.json> --root <servi> <servi>/lists/*.txt
# le rapport d'un jour donné, tiré du journal
node tools/blocklist-mirror.mjs report <servi> --day 2026-10-06 --out /tmp/rapport.txt
<publiques.json> contient { "keys": [ … ] }, les mêmes entrées que le tableau keys de hardening/ubo-patch/navkrypt-list-keys.js.
5.3 Lire le journal à la main
Le journal est du JSON, une ligne par événement, jamais réécrit :
grep -c '"etape":"verification"' deploy/blocklist-mirror/journal-2026-10-06-M3.log # 18 vérifications
grep '"verdict":"refusee"' deploy/blocklist-mirror/journal-2026-10-06-M3.log # les 2 refus
Chaque ligne "etape":"mise-en-ligne" doit être précédée d'une ligne "etape":"verification" de la même liste, avec le même sha256 et "verdict":"ok". C'est exactement ce que contrôle audit.
5.4 Rejouer les preuves du dépôt
node --test tests/ubo-patch.test.mjs # exécute le vrai assets.js d'uBO 1.75.0 patché
node --test tests/blocklist-mirror.test.mjs # la porte, par la ligne de commande
node --test tests/guide-verification-listes.test.mjs # ce guide confronté au code
node tools/sabotage.mjs run --only guide-listes-motif-navigateur,guide-listes-message-confirmation
6. Opérateur : clés et installation
- Créer la clé de production sur la machine du miroir, jamais ailleurs :
node tools/ubo-list-signature.mjs keygen nk-listes-1 /etc/navkrypt. La clé privée est écrite en0600, et l'outil refuse d'écraser une clé existante. L'entrée publique affichée est à verser danskeysdehardening/ubo-patch/navkrypt-list-keys.js. - Changer de clé : créer une clé de nouveau
kid, ajouter sa partie publique àkeysà côté de l'ancienne, livrer ce navigateur, puis seulement signer avec la nouvelle. Le navigateur cherche la clé par sonkid: tant que l'ancienne est danskeys, les listes déjà signées restent valides (30 jours au plus). - Installer la tâche quotidienne :
deploy/blocklist-mirror/README.md, § Installation. - Porter le patch dans uBO au build :
node tools/ubo-list-signature.mjs apply <depot-uBlock>.applyrefuse une version d'uBO autre que celle épinglée (hardening/ubo-patch/UPSTREAM.json) : une autre version demande un patch réécrit, pas un patch forcé.
7. État au 2026-10-06 — ce qui est en place, ce qui ne l'est pas encore
Dit franchement, parce qu'une vérification annoncée mais absente serait pire que pas de vérification :
- Fait : la porte de publication, le journal, l'audit, le rapport quotidien et la signature existent et sont testés (y compris par sabotage) ;
- Fait : le patch d'uBO existe et est testé sur le vrai code d'uBO 1.75.0 ;
- À venir : le uBO livré aujourd'hui vient d'AMO, non patché : un uBO patché est une extension reconstruite, distribuée par Navkrypt (build sur le hub) ;
- À venir : le miroir n'est pas encore en service : machine UE, nom servi (
https://listes.navkrypt.euest une proposition) et clé de production restent à poser par le porteur ; - Verrou : tant qu'aucune clé n'est livrée,
keysest vide et toute liste du miroir est refusée (motifcle-inconnue) : on ne laisse jamais passer faute de clé.
Références : deploy/blocklist-mirror/README.md (porte, installation), hardening/ubo-patch/README.md (patch, preuves), tools/blocklist-mirror.mjs, tools/ubo-list-signature.mjs.