

ppush.online : partager un secret, proprement
Pourquoi et comment j'ai cloné Password Pusher, en version zéro-knowledge : le paysage, les tarifs, la stack, la conformité et les pièges évités.
Tout le monde a déjà collé un mot de passe dans un Slack, un mail ou un SMS « le temps que tu le notes ». Sauf que le message reste : dans l’historique, dans les sauvegardes, dans l’index de recherche. ppush.online ↗ remplace ça par un lien chiffré, à usage limité, qui s’autodétruit.
Soyons clairs tout de suite : ce n’est pas une révolution. Le partage de secrets éphémères chiffrés côté client existe depuis des années (Password Pusher, OneTimeSecret, Bitwarden Send, 1Password…). ppush est un clone libre et complet de Password Pusher ↗, avec les fonctions « PRO » débloquées, autant que possible.
Note: Ce projet a été écrit en orchestrant l’IA (ici Claude, Opus 4.8, majoritairement)

1. Le problème : un secret partagé en clair ne se reprend pas#
Envoyer un secret « en clair » a trois défauts qu’on sous-estime :
- Persistance : le message survit bien après son utilité (historiques, notifications push, backups, e-discovery).
- Diffusion : copié-collé, transféré, screenshoté — tu perds le contrôle.
- Aucune révocation : une fois parti, impossible de le « reprendre ».
La parade est connue : un lien à usage unique qui pointe vers un secret chiffré, avec une expiration (par vues et par durée). Le secret vit le temps de la transmission, puis disparaît. C’est exactement le périmètre de ppush.
2. Le paysage et les tarifs#
Avant de réinventer la roue, regardons ce qui existe. Tarifs relevés en juin 2026 (ça bouge, vérifie à la source) :
| Service | Modèle | Partage éphémère | Tarif |
|---|---|---|---|
| Password Pusher (auto hébergé) | SaaS + open source | Oui (texte/URL gratuit) | Free ; Premium 19 /mois (5 sièges, SSO) ; self-host Pro dès 59 $/mois |
| OneTimeSecret | SaaS + open source | Oui | Basic gratuit ; Identity Plus 35 €/mois ; équipes uniquement en self-host |
| Bitwarden Send | Inclus au gestionnaire | Oui (texte gratuit) | Texte gratuit ; fichiers = Premium (≈ 10–20 $/an) |
| 1Password | Gestionnaire | Oui (liens de partage) | Partage inclus dans l’abo (≈ 3 $/mois et +) |
| PrivateBin / Yopass | Open source | Oui | Gratuit, à self-héberger |
| ppush.online | Service public gratuit | Oui (tout type) | Gratuit, sans mur PRO |
Deux constats honnêtes :
- Le zéro-knowledge et l’éphémère ne sont pas des nouveautés
- La plupart des offres réservent les fichiers, le suivi ou le branding au payant. ppush fait le pari inverse : tout est ouvert, le seul garde-fou est un fair-use transparent sur le stockage (j’y reviens).
ppush n’est donc « mieux » que sur un axe : c’est un clone gratuit qui ne planque rien derrière un paywall. Pour un usage pro avec SLA, support et white-label, Password Pusher Pro reste évidemment un choix tout à fait légitime.
3. Le zéro-knowledge#
Le principe tient en une phrase : le serveur ne voit jamais le secret en clair, ni la clé.
- Le navigateur génère une clé AES-256 aléatoire et chiffre le secret localement (AES-256-GCM, WebCrypto).
- Seul le ciphertext part vers le serveur.
- La clé voyage dans le fragment d’URL (
…/p/<slug>#<clé>) — et les fragments#ne sont jamais transmis par les navigateurs au serveur. - Le destinataire déchiffre en local. À l’expiration, le ciphertext est purgé.
Le format chiffré est volontairement bête et versionné — [version][IV 12o][ciphertext+tag] :
export async function encryptPayload(key: CryptoKey, payload: SecretPayload) {
const iv = crypto.getRandomValues(new Uint8Array(12)); // IV 96 bits, unique
const ct = new Uint8Array(await subtle().encrypt(
{ name: "AES-GCM", iv, additionalData: te.encode("ppush:v1:meta") },
key, te.encode(JSON.stringify(payload))
));
const out = new Uint8Array(1 + 12 + ct.length);
out[0] = 1; out.set(iv, 1); out.set(ct, 13); // [v1][IV][ct+tag]
return out;
}tsNote — Une fuite complète de la base de données ne révèle aucun secret : elle ne contient que des ciphertexts. La sécurité repose sur les maths (AES-GCM), pas sur une promesse de bonne conduite du serveur. C’est ce qui permet de dire, sans bluff, que même l’admin ne peut pas lire tes secrets.
Côté réseau, le trafic passe par Cloudflare (diffusion + anti-DDoS), qui ne
voit lui non plus que du chiffré — la clé n’est jamais dans l’URL envoyée, ni dans
un Referer. Cloudflare n’est qu’un relais ; les données restent hébergées en
France.
4. Les fonctionnalités qui comptent#
- 4 types de pushes : mot de passe, texte, fichier (chiffré par chunks de 8 Mio, avec AAD anti-réordonnancement) et URL (redirection après déchiffrement).
- Double expiration : par nombre de vues et par durée — le premier seuil atteint gagne. Granularité en minutes (de 5 min à plusieurs jours).
- Passphrase optionnelle : hachée en Argon2id côté serveur (OWASP 2025 : m = 19 Mio, t = 2, p = 1) et rate-limitée.
- Étape « cliquer pour révéler » : les aperçus automatiques (messageries, antivirus, link unfurling) ne brûlent pas une vue. Détail crucial, j’y reviens.
- Passkeys (WebAuthn) : inscription et connexion passwordless, vérification utilisateur (UV) imposée — résistant au hameçonnage.
- Générateur de mots de passe côté client : CSPRNG + rejection sampling, longueur 8–64, classes paramétrables, ambigus exclus par défaut, entropie en bits.
- API REST + tokens et un CLI zéro-knowledge (le chiffrement reste local) :
export PPUSH_URL=https://ppush.online
export PPUSH_TOKEN=ppush_xxx
tools/ppush-cli.mjs --password "S3cret!" --views 3 --days 7
tools/ppush-cli.mjs --file dump.sql.gz --passphrase "sesame" --note "backup pour Bob"
# → imprime l'URL complète, clé incluse dans le fragment #bash
Avec un compte gratuit, on débloque l’historique, le suivi des consultations (qui a ouvert, quand, depuis quelle IP), des fichiers plus lourds (90 Mo vs 10 Mo en anonyme) et des rétentions plus longues. Sans compte, le partage reste possible — juste plus léger et pour des durées plus courtes.

Le fair-use, mais transparent#
Service gratuit = espace fichiers partagé. Plutôt qu’un quota opaque, ppush
expose la réalité : une API publique GET /api/storage renvoie l’espace
réellement disponible et les libérations à venir (par date d’expiration).
À saturation, l’upload renvoie un HTTP 507 avec un message du genre « X
seront libérés au plus tard dans Y », pour réessayer au bon moment. Un sweeper
purge les payloads expirés et les blobs orphelins toutes les 10 minutes.
On est sur un petit projet, et pour le moment c’est le modèle que j’ai choisi.
5. La stack#
Rien d’exotique, et c’est volontaire — une stack ennuyeuse est une stack qu’on maintient facilement :
- Next.js 16 (App Router) · TypeScript · Tailwind 4
- Prisma 7 + SQLite (adapter
better-sqlite3) — un seul fichier de base, zéro serveur SQL à babysitter - Argon2id (
@node-rs/argon2) · WebCrypto pour tout le chiffrement - next-intl : i18n complète FR/EN, aucune chaîne en dur
- Docker : l’appli est un conteneur autonome
L’infra de prod, c’est une machine dédiée en France, derrière Cloudflare.
Mais comme tout est conteneurisé et que la base est un simple fichier SQLite,
migrer vers n’importe quel hébergeur (VPS, PaaS, cloud) est une formalité :
docker compose up, un volume pour data/, et c’est reparti. Aucune dépendance à
un service managé propriétaire. Je ferais une migration en temps voulu, si nécessaire.
6. Conformité (RGPD / LCEN)#
Un service public qui touche à des données, ça implique du sérieux côté droit — pas juste côté crypto :
- Suppression self-service : on supprime son compte et tout son contenu (pushes, sessions, passkeys, tokens) immédiatement et définitivement, sans intervention humaine. Puis on peut recréer un compte à neuf.
- Journal de connexion légal : seule exception à la suppression, imposée par la loi — un log minimal (IP + horodatage), dissocié de l’identité, conservé le temps de l’obligation hébergeur (~12 mois) puis purgé. Ni secrets, ni profil.
- Anonymisation : les IP du journal d’audit sont anonymisées au-delà de la fenêtre légale.
- Pas d’email de réinitialisation — choix assumé (voir pièges ci-dessous).
Bases légales, durées de conservation et droits sont détaillés dans les pages Mentions légales et Confidentialité du site. Le tout est présenté sans sur-promesse : projet personnel, auto-financé, fourni « en l’état », sans garantie de disponibilité. ppush n’est pas un service de sauvegarde — garde toujours une copie de tes infos ailleurs.
7. Les pièges évités#
C’est là que se joue la différence entre « ça marche en démo » et « ça tient en prod ». Quelques exemples, avec leur correctif.
Problème : la clé de déchiffrement qui fuit#
Mettre la clé dans une query string (?key=…), c’est la voir partir dans les logs
serveur, l’historique du navigateur et l’en-tête Referer. Fix : la clé vit
uniquement dans le fragment # (jamais transmis au serveur) + Referrer-Policy
strict pour qu’aucune navigation ne la laisse fuir.
Password.link utilise cette technique depuis 2016.
Problème : les aperçus qui brûlent une vue#
Slack, WhatsApp, un antivirus d’entreprise… unfurlent les liens en arrière-plan.
Si la vue est décomptée au GET de la page, le secret « 1 vue » est consommé
avant que l’humain n’ouvre le lien. Fix : une étape explicite « cliquer
pour révéler ». La vue n’est décomptée qu’au POST /reveal, sur action humaine.
Si cette option n’est pas choisie, ce que l’utilisateur peut décider dans les options, alors tant pis pour lui ;)
Problème : la course (race condition) sur la dernière vue#
Deux requêtes simultanées sur un secret à 1 vue restante pourraient le révéler deux fois. Fix : réservation atomique de la vue en base avant de servir le ciphertext, et jeton de téléchargement à usage unique pour les fichiers (délivré seulement après passphrase + décompte).
Problème : l’IP cliente spoofée#
Le rate limiting par IP ne vaut rien si le client peut forger X-Forwarded-For.
Fix : on lit la dernière entrée du X-Forwarded-For (celle posée par le
reverse proxy de confiance), non contrôlable par le client. À voir dans le temps si ça suffit !
Problème : l’email de reset, vecteur de prise de contrôle#
Les liens de réinitialisation par email sont une famille entière d’attaques (interception, hameçonnage, boîte compromise). Fix : ppush n’envoie aucun email de reset. La récupération est vérifiée par un humain via une page dédiée. La contrepartie (pas instantané) est assumée : l’enjeu reste faible, un compte ne contient que l’historique et les préférences — aucun secret n’est pris en otage. Le vrai filet, c’est la passkey.
Problème : une CSP permissive#
Une Content-Security-Policy avec unsafe-inline, c’est la porte ouverte au XSS.
Fix : CSP à nonce (pas d’inline arbitraire), plus HSTS, X-Frame-Options
et anti-CSRF par vérification d’Origin sur toute mutation.

Résultat#
| Aspect | État |
|---|---|
| Zéro-knowledge | Chiffrement client AES-256-GCM, clé jamais transmise |
| Types de secrets | Mot de passe · texte · fichier · URL |
| Comptes | Optionnels ; passkeys + 2FA TOTP ; suppression self-service |
| Conformité | RGPD / LCEN, journal légal dissocié ~12 mois |
| Accès | Web responsive + API REST + CLI |
| Coût | Gratuit, sans fonction réservée au payant |
| Portabilité | Conteneur + SQLite → migrable easy |

Au final, ppush ne prétend rien révolutionner : il applique proprement des pratiques connues, sans paywall, et en soignant les détails qui font qu’un secret ne fuite pas par accident. Donc si tu veux juste envoyer un mot de passe sans qu’il traîne n’importe-où, c’est par ici ↗ ! :-)