Salta ai contenuti

Integrazione del Server

Processo di verifica PoW

Il processo di verifica si basa sul lavoro computazionale (SHA-hashing) e coinvolge i seguenti passaggi:

  1. Recupera la challenge dal lato client.
  2. Determina la soluzione alla sfida.
  3. Invia sia la soluzione che i dati dell’utente al server.
  4. Convalida la soluzione e la firma sul server.

L’aspetto del lato client è gestito dal widget ALTCHA, mentre è necessaria l’implementazione della verifica lato server. Il gestore di invio del server (ad es. POST /form_submit) deve autenticare il payload ALTCHA al momento dell’invio del modulo.

Fai riferimento alla documentazione sulla prova di lavoro per ulteriori informazioni sul meccanismo dietro ALTCHA.

Complessità

Generare una nuova sfida coinvolge tre passaggi di calcolo SHA (una volta per la sfida e due volte per la firma HMAC). Allo stesso modo, verificare una soluzione richiede anche tre passaggi.

L’intervallo del numero casuale regola la difficoltà del compito computazionale richiesto dal client.

Per maggiori dettagli, fai riferimento all’aggiustamento della complessità.

Server

Il server deve generare una nuova sfida per ciascuna verifica ALTCHA. Ci sono due metodi per fornire la sfida al widget:

  1. Usando challengeurl: Se configurato, il widget recupera la sfida dall’URL specificato. Il server deve restituire una nuova sfida come descritto di seguito.

  2. Usando challengejson: Fornire direttamente la sfida come stringa JSON-encoded. Questo metodo è utile per le pagine renderizzate lato server.

Per ulteriori dettagli sul meccanismo di prova di lavoro, leggi di più.

Creazione di una sfida

Di seguito è riportato un esempio di pseudo-codice per la creazione di una sfida sul server:

// Genera un salt casuale (lunghezza consigliata: almeno 10 caratteri)
salt = random_string();
// Genera un numero segreto casuale (intero positivo)
// L'intervallo dipende dalla complessità scelta (fare riferimento alla documentazione)
// Assicurarsi di NON esporre questo numero al client
secret_number = random_int();
// Calcola l'hash SHA256 del salt concatenato con il numero segreto (risultato codificato come stringa HEX)
challenge = sha2_hex(concat(salt, secret_number));
// Crea una firma del server utilizzando una chiave HMAC (risultato codificato come stringa HEX)
signature = hmac_sha2_hex(challenge, hmac_key);
// Ritorna i dati codificati in JSON
response = {
algorithm = 'SHA-256',
challenge,
salt,
signature,
};

Parametri di Sale

A partire dalla versione del Widget v0.4 (maggio 2024), è consigliato includere il flag expires e parametri aggiuntivi nel salt come stringhe di query codificate in URL. Ciò consente di passare dati personalizzati, che faranno parte della firma e saranno verificabili sul server.

Il widget rileva automaticamente il parametro expires quando fornito nel sale come timestamp Unix in secondi:

salt = '<random_salt>?expires=1715526540'

Per garantire la compatibilità con le future versioni del widget, è consigliabile prefissare eventuali parametri personalizzati con un trattino basso _.

La libreria altcha-lib supporta già i parametri di sale e verifica automaticamente la scadenza della sfida dalla versione v0.3.

Invio del modulo

Al momento dell’invio entro un <form>, il server riceverà dati codificati come application/x-www-form-urlencoded o multipart/form-data, a seconda della struttura del modulo. Il payload ALTCHA sarà incorporato come campo altcha (personalizzabile tramite l’attributo name nel widget).

Utilizza il valore del campo altcha come payload negli esempi seguenti. Il payload è una stringa codificata in Base64-JSON.

Convalida della soluzione

Di seguito è riportato un esempio di pseudo-codice per convalidare una soluzione sul server:

// Il payload è una stringa codificata in BASE64-JSON
// I dati decodificati sono un oggetto contenente { algoritmo, sfida, numero, salt, firma }
data = json_decode(base64_decode(payload));
// Convalida algoritmo
alg_ok = equals(data.algorithm, 'SHA-256');
// Convalida sfida
challenge_ok = equals(data.challenge, sha2_hex(concat(data.salt, data.number)))
// Convalida firma
signature_ok = equals(data.signature, hmac_sha2_hex(data.challenge, hmac_key))
// Considera la richiesta verificata se tutti i controlli sono veri
verified = alg_ok and challenge_ok and signature_ok

Esempio

La libreria JS ufficiale funziona con Node.js, Bun e Deno.

server.js
import { createChallenge, verifySolution } from 'altcha-lib';
const hmacKey = '$ecret.key'; // Cambia la chiave HMAC segreta
// Crea una nuova sfida e inviala al client:
const challenge = await createChallenge({
hmacKey,
});
// Quando inviato, verifica il payload:
const ok = await verifySolution(payload, hmacKey);

Per ulteriori esempi e integrazioni, fai riferimento alla pagina Integrazioni della Community.

Raccomandazioni sulla sicurezza

  • Attacchi di ripetizione

    Per prevenire la vulnerabilità degli “attacchi di ripetizione”, in cui un client invia la stessa soluzione più volte, il server dovrebbe implementare misure che invalidano le sfide risolte in precedenza.

    Il server dovrebbe mantenere un registro delle sfide risolte e rifiutare eventuali invii che tentano di riutilizzare una sfida che è stata già risolta con successo.

  • Scadenza della sfida

    Limitare il periodo di validità delle sfide può rafforzare le misure di sicurezza, garantendo che le sfide non possano essere sfruttate indefinitamente. Implementare la scadenza della sfida comporta l’imposizione di un limite di tempo entro il quale una sfida deve essere risolta e inviata.

    Un metodo efficace per raggiungere la scadenza della sfida coinvolge l’incorporazione di un timestamp del server nel salt della sfida durante la sua generazione.

    A partire dalla versione 0.4 del widget, è possibile utilizzare parametri di sale e includere il parametro ?expires=<unix_ts> nel sale. Il widget rileverà automaticamente il parametro expires. Il tuo server dovrebbe quindi verificare la scadenza durante il processo di verifica.