Aller au contenu

Intégration du serveur

Processus de vérification PoW

Le processus de vérification repose sur un travail computationnel (hachage SHA) et comprend les étapes suivantes :

  1. L’utilisateur lance le processus de vérification.
  2. Le widget fait une demande à challengeurl pour récupérer les données du défi.
  3. Le widget traite et résout le défi en fonction des données récupérées.
  4. L’utilisateur soumet le formulaire contenant le défi résolu.
  5. Le serveur vérifie la charge utile dans la soumission du formulaire pour s’assurer qu’elle correspond à la solution attendue du défi.

L’aspect côté client est géré par le widget ALTCHA, tandis que la mise en œuvre de la vérification côté serveur est requise. Le gestionnaire de soumission du serveur (par exemple, POST /form_submit) doit authentifier la charge utile ALTCHA lors de la soumission du formulaire.

Consultez la documentation de preuve de travail pour en savoir plus sur le mécanisme derrière ALTCHA.

Complexité

Générer un nouveau challenge implique trois passes de calcul SHA (une fois pour le challenge et deux fois pour la signature HMAC). De même, la vérification d’une solution nécessite également trois passes.

La plage du nombre aléatoire ajuste la difficulté de la tâche computationnelle requise du client.

Pour plus de détails, consultez l’ajustement de la complexité.

Serveur

Le serveur doit générer un nouveau challenge pour chaque vérification ALTCHA. Il existe deux méthodes pour fournir le challenge au widget :

  1. Utilisation de challengeurl : Si configuré, le widget récupère le challenge à partir de l’URL spécifiée. Le serveur doit renvoyer un nouveau challenge comme décrit ci-dessous.

  2. Utilisation de challengejson : Fournir directement le challenge sous forme de chaîne encodée en JSON. Cette méthode est utile pour les pages rendues côté serveur.

En savoir plus sur le mécanisme de preuve de travail.

Création d’un challenge

Voici un exemple de pseudo-code pour créer un challenge sur le serveur :

// Choisissez la complexité - le nombre aléatoire maximal (voir la documentation sur la complexité)
maxnumber = 100_000;
// Générez un sel aléatoire (longueur recommandée : au moins 10 caractères)
salt = random_string();
// Générez un nombre secret aléatoire (entier positif)
// Plage entre 0...maxnumber
// Veillez à NE PAS exposer ce nombre au client
secret_number = random_int(maxnumber);
// Calculez le hachage SHA-256 du sel + secret_number concaténés (résultat encodé en chaîne HEX)
challenge = sha2_hex(concat(salt, secret_number));
// Créez une signature serveur en utilisant une clé HMAC (résultat encodé en chaîne HEX)
signature = hmac_sha2_hex(challenge, hmac_key);
// Retournez les données encodées en JSON
response = {
algorithm: 'SHA-256',
challenge,
maxnumber,
salt,
signature,
};

Lorsque le paramètre maxnumber est renvoyé au client, le widget ALTCHA peut mieux optimiser la distribution de la charge de travail entre plusieurs travailleurs, ce qui le rend plus rapide. Les bibliothèques officielles renvoient par défaut la valeur maxnumber car cela est généralement recommandé. En fonction de votre cas d’utilisation, le paramètre maxnumber pourrait être considéré comme un paramètre secret qui ne doit pas être exposé au client car il révèle la plage du nombre. Dans des cas spécifiques où vous souhaitez une difficulté élevée, comme M2M ou des intégrations personnalisées, ne renvoyez pas maxnumber.

Paramètres de Sel

À partir de la version du Widget v0.4 (mai 2024), il est recommandé d’inclure le drapeau expires et des paramètres supplémentaires dans le salt sous forme de chaînes de requête encodées en URL. Cela vous permet de transmettre des données personnalisées, qui feront partie de la signature et pourront être vérifiées sur le serveur.

Le widget détecte automatiquement le paramètre expires lorsqu’il est fourni dans le sel sous forme de timestamp Unix en secondes :

salt = '<random_salt>?expires=1715526540'

Pour assurer la compatibilité avec les futures versions du widget, il est recommandé de préfixer tout paramètre personnalisé avec un trait de soulignement _.

La bibliothèque altcha-lib prend déjà en charge les paramètres de sel et vérifie automatiquement l’expiration du défi à partir de la version v0.3.

Soumission de formulaire

Lors de la soumission dans un élément <form>, le serveur recevra des données encodées en application/x-www-form-urlencoded ou multipart/form-data, selon la structure du formulaire. La charge utile ALTCHA sera incorporée en tant que champ altcha (personnalisable via l’attribut name dans le widget).

Utilisez la valeur du champ altcha comme payload dans les exemples ci-dessous. La charge utile est une chaîne encodée en Base64-JSON.

Validation de la solution

Voici un exemple de pseudo-code pour valider une solution sur le serveur :

// La charge utile est une chaîne encodée BASE64-JSON
// Les données décodées sont un objet contenant { algorithm, challenge, number, salt, signature }
data = json_decode(base64_decode(payload));
// Valider l'algorithme
alg_ok = equals(data.algorithm, 'SHA-256');
// Valider le challenge
challenge_ok = equals(data.challenge, sha2_hex(concat(data.salt, data.number)))
// Valider la signature
signature_ok = equals(data.signature, hmac_sha2_hex(data.challenge, hmac_key))
// Considérer la demande comme vérifiée si toutes les vérifications sont vraies
verified = alg_ok and challenge_ok and signature_ok

Exemple

La bibliothèque JS officielle fonctionne avec Node.js, Bun et Deno.

server.js
import { createChallenge, verifySolution } from 'altcha-lib';
const hmacKey = '$ecret.key'; // Changer la clé secrète HMAC
// Créer un nouveau challenge et l'envoyer au client :
const challenge = await createChallenge({
hmacKey,
});
// Lors de la soumission, vérifiez la charge utile :
const ok = await verifySolution(payload, hmacKey);

Pour plus d’exemples et d’intégrations, consultez la page des Intégrations de la communauté.

Recommandations de sécurité

  • Attaques de rejeu

    Pour prévenir la vulnérabilité des “attaques de rejeu”, où un client soumet la même solution plusieurs fois, le serveur doit mettre en place des mesures qui invalident les défis résolus précédemment.

    Le serveur doit maintenir un registre des défis résolus et rejeter toutes les soumissions qui tentent de réutiliser un défi qui a déjà été résolu avec succès.

  • Expiration du challenge

    Limiter la période de validité des défis peut renforcer les mesures de sécurité, assurant que les défis ne peuvent pas être exploités indéfiniment. Mettre en place l’expiration du défi implique de définir une limite de temps dans laquelle un défi doit être résolu et soumis.

    Une méthode efficace pour atteindre l’expiration du défi consiste à incorporer un horodatage du serveur dans le salt du défi lors de sa génération.

    À partir de la version 0.4 du widget, vous pouvez utiliser les paramètres de sel et inclure le paramètre ?expires=<unix_ts> dans le sel. Le widget détectera automatiquement le paramètre expires. Votre serveur devra alors vérifier l’expiration lors du processus de vérification.