Saltearse al contenido

Integración del Servidor

Proceso de verificación PoW

El proceso de verificación se basa en el trabajo computacional (SHA-hashing) e implica los siguientes pasos:

  1. Recuperar el challenge en el lado del cliente.
  2. Determinar la solución al desafío.
  3. Enviar tanto la solución como los datos del usuario al servidor.
  4. Validar la solución y la firma en el servidor.

El aspecto del lado del cliente es gestionado por el widget ALTCHA, mientras que se requiere la implementación de la verificación en el lado del servidor. El manejador de envíos del servidor (por ejemplo, POST /form_submit) necesita autenticar el payload de ALTCHA al enviar el formulario.

Consulte la documentación de prueba de trabajo para obtener más información sobre el mecanismo detrás de ALTCHA.

Complejidad

Generar un nuevo desafío implica tres pasadas de cálculo de SHA (una vez para el desafío y dos veces para la firma HMAC). De manera similar, verificar una solución también requiere tres pasadas.

El rango del número aleatorio ajusta la dificultad de la tarea computacional requerida por el cliente.

Para más detalles, consulte ajustando la complejidad.

Servidor

El servidor debe generar un nuevo desafío para cada verificación de ALTCHA. Hay dos métodos para proporcionar el desafío al widget:

  1. Utilizando challengeurl: Si está configurado, el widget obtiene el desafío desde la URL especificada. El servidor debe devolver un nuevo desafío como se describe a continuación.

  2. Utilizando challengejson: Proporcione directamente el desafío como una cadena codificada en JSON. Este método es útil para páginas renderizadas en el servidor.

Lea más sobre el mecanismo de prueba de trabajo.

Creando un desafío

Aquí hay un ejemplo de pseudo-código para crear un desafío en el servidor:

// Generar una sal aleatoria (longitud recomendada: al menos 10 caracteres)
salt = random_string();
// Generar un número secreto aleatorio (entero positivo)
// El rango depende de la complejidad elegida (consulte la documentación)
// Asegúrese de NO exponer este número al cliente
secret_number = random_int();
// Calcular el hash SHA256 de la concatenación de la sal + secret_number (resultado codificado como cadena HEX)
challenge = sha2_hex(concat(salt, secret_number));
// Crear una firma del servidor usando una clave HMAC (resultado codificado como cadena HEX)
signature = hmac_sha2_hex(challenge, hmac_key);
// Devolver datos codificados en JSON
response = {
algorithm = 'SHA-256',
challenge,
salt,
signature,
};

Parámetros de Sal

A partir de la versión del Widget v0.4 (Mayo de 2024), se recomienda incluir el indicador expires y parámetros adicionales en el salt como cadenas de consulta codificadas en URL. Esto le permite pasar datos personalizados, que formarán parte de la firma y serán verificables en el servidor.

El widget detecta automáticamente el parámetro expires cuando se proporciona en el salt como una marca de tiempo Unix en segundos:

salt = '<random_salt>?expires=1715526540'

Para garantizar la compatibilidad con futuras versiones del widget, se recomienda agregar un guion bajo _ como prefijo a cualquier parámetro personalizado.

La biblioteca altcha-lib ya admite parámetros de sal y verifica automáticamente la expiración del desafío desde la versión v0.3.

Envío del formulario

Al enviar dentro de un <form>, el servidor recibirá datos codificados como application/x-www-form-urlencoded o multipart/form-data, dependiendo de la estructura del formulario. El payload de ALTCHA estará incrustado como el campo altcha (personalizable a través del atributo name en el widget).

Use el valor del campo altcha como el payload en los ejemplos a continuación. El payload es una cadena codificada Base64-JSON.

Validación de la solución

Aquí hay un ejemplo de pseudo-código para validar una solución en el servidor:

// El payload es una cadena codificada en BASE64-JSON
// Los datos decodificados son un objeto que contiene { algoritmo, desafío, número, salt, firma }
data = json_decode(base64_decode(payload));
// Validar algoritmo
alg_ok = equals(data.algorithm, 'SHA-256');
// Validar desafío
challenge_ok = equals(data.challenge, sha2_hex(concat(data.salt, data.number)))
// Validar firma
signature_ok = equals(data.signature, hmac_sha2_hex(data.challenge, hmac_key))
// Considerar la solicitud verificada si todas las comprobaciones son verdaderas
verified = alg_ok and challenge_ok and signature_ok

Ejemplo

La librería JS oficial funciona con Node.js, Bun y Deno.

server.js
import { createChallenge, verifySolution } from 'altcha-lib';
const hmacKey = '$ecret.key'; // Cambie la clave secreta HMAC
// Crear un nuevo desafío y enviarlo al cliente:
const challenge = await createChallenge({
hmacKey,
});
// Al enviar, verificar el payload:
const ok = await verifySolution(payload, hmacKey);

Para más ejemplos e integraciones, consulte la página de Integraciones de la Comunidad.

Recomendaciones de seguridad

  • Ataques de repetición

    Para prevenir la vulnerabilidad de “ataques de repetición”, donde un cliente reenvía la misma solución varias veces, el servidor debe implementar medidas que invaliden desafíos previamente resueltos.

    El servidor debe mantener un registro de desafíos resueltos y rechazar cualquier envío que intente reutilizar un desafío que ya ha sido resuelto con éxito.

  • Caducidad del desafío

    Limitar el período de validez de los desafíos puede fortalecer las medidas de seguridad, asegurando que los desafíos no puedan ser explotados indefinidamente. Implementar la caducidad del desafío implica establecer un límite de tiempo dentro del cual un desafío debe ser resuelto y enviado.

    Un método efectivo para lograr la caducidad del desafío implica incorporar un sello de tiempo del servidor en la salt del desafío durante su generación.

    A partir de la versión 0.4 del widget, puede utilizar parámetros de sal e incluir el parámetro ?expires=<unix_ts> en el salt. El widget detectará automáticamente el parámetro expires. Su servidor deberá entonces verificar la expiración durante el proceso de verificación.