Aller au contenu
~/lylylinked

$ man installer-devtcha-nextjs

Installer devTcha sur un formulaire Next.js

Une protection anti-robot par preuve de travail, sans cookie, sans service tiers et sans image à déchiffrer. Voici comment elle est branchée sur le formulaire d’audit de ce site.

pour qui
  • Vous avez un formulaire public et vous ne voulez pas de reCAPTCHA.
  • Vous tenez à ne rien envoyer à un tiers, pour vos visiteurs comme pour le RGPD.
  • Vous cherchez un exemple complet plutôt qu’un bout de code hors contexte.
à quoi ça sert

À faire résoudre un petit calcul au navigateur avant l’envoi : peu coûteux pour une personne, cher pour un robot qui répète.

quand l’utiliser
  • Dès qu’un formulaire public déclenche un traitement : envoi d’un message, appel à une API, écriture en base.
  • Quand une case à cocher d’un service tiers vous gêne, pour la vie privée ou pour l’accessibilité.

01Le principe, en une phrase

Le serveur fabrique un défi, le navigateur cherche le nombre dont l’empreinte correspond, puis renvoie sa trouvaille avec le formulaire. Le serveur vérifie, et refuse un défi déjà utilisé.

Rien à déchiffrer, aucune case à cocher, aucune requête vers un autre domaine que le vôtre. Le visiteur ne voit qu’une ligne qui se coche toute seule.

La page du projet en propose une démonstration, sur un formulaire d’essai : c’est le moyen le plus rapide de voir ce que ça donne avant d’installer quoi que ce soit.

Le formulaire d’audit affichant « Vérification anti-robot effectuée »
Ce que voit le visiteur : la vérification s’est faite pendant qu’il tapait.

02Installer et tirer un secret

Le paquet est publié sur npm, sans dépendance, sous licence MIT.

terminal
npm install devtcha

# un secret d’au moins 32 caractères, devTcha refuse en deçà
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
La fiche du paquet devtcha sur npm
Zéro dépendance, et des serveurs en Node, PHP, Python et Go.

Le secret va dans les variables d’environnement. Il ne sort jamais du serveur : c’est lui qui signe les défis, et c’est sur lui que repose toute la protection, pas sur le secret du code.

03La route qui délivre un défi

Un appel, un défi. Jamais de cache : un défi rejoué n’en est plus un.

pages/api/devtcha.js
import { createChallenge } from 'devtcha/server';

export default function handler(req, res) {
  res.setHeader('Cache-Control', 'no-store');
  res.status(200).json(
    createChallenge({ secret: process.env.DEVTCHA_SECRET })
  );
}

04La route qui vérifie

Le jeton arrive avec le formulaire. Tant qu’il n’est pas validé, le traitement n’a pas lieu.

pages/api/mon-traitement.js
import { verifySolution } from 'devtcha/server';

const verdict = await verifySolution(req.body.devtcha, {
  secret: process.env.DEVTCHA_SECRET,
});

if (verdict !== 'ok') {
  return res.status(400).json({ message: 'Vérification échouée.' });
}

// ... le traitement protégé

La fonction répond « ok », « invalid », « expired » ou « reused ». Ce dernier cas mérite d’être connu : un même défi ne sert qu’une fois, et rejouer un jeton pourtant valide est refusé.

05Le widget, côté navigateur

Le composant se déclare en important le client. Il retient l’envoi le temps du calcul, puis remplit lui-même un champ caché.

components/MonFormulaire.jsx
useEffect(() => {
  import('devtcha/client');
}, []);

// dans le formulaire
<dev-tcha challengeurl="/api/devtcha" name="devtcha" />

06Le piège qui m’a coûté une relecture

Avant la publication du paquet, j’avais écrit les imports avec un commentaire « webpackIgnore », pour que la construction ne se plaigne pas d’un module absent. Une fois le paquet installé, l’avoir laissé aurait été pire que rien.

Next n’embarque pas une dépendance qu’on lui demande d’ignorer. L’import aurait échoué en production, le code serait retombé sur sa protection de secours, et la page aurait continué d’annoncer que devTcha était actif. Une protection qui ment sur elle-même ne protège rien.

  • Retirez les « webpackIgnore » dès que la dépendance est réelle.
  • Contrôlez la longueur du secret, devTcha en exige trente-deux.
  • Décidez ce que fait la route si le secret manque, et dites-le au visiteur.

07Vérifier que ça marche vraiment

Un formulaire qui s’envoie ne prouve rien. Ce qui prouve, c’est qu’un jeton rejoué soit refusé. Sur ce site, le tour complet donne ceci.

quatre envois sur la route protégée
jeton valide           200   audit rendu
le même jeton rejoué   400   verification_echouee
jeton inventé          400   verification_echouee
sans jeton             400   verification_echouee

Pour fabriquer un jeton valide hors navigateur, il suffit de chercher le nombre dont l’empreinte SHA-256 du sel suivi du nombre vaut le défi, puis d’encoder le tout en base64. C’est ce que fait le widget, en arrière-plan.

$ open installer-devtcha-nextjs

Ce service est tenu par quelqu’un d’autre : l’inscription et les candidatures se font chez lui.

devtchacaptcha sans cookiealternative reCAPTCHApreuve de travailNext.js