Pular para o conteúdo

Integração de Servidor

Processo de verificação PoW

O processo de verificação baseia-se no trabalho computacional (SHA-hashing) e envolve as seguintes etapas:

  1. Recuperar o challenge no lado do cliente.
  2. Determinar a solução para o desafio.
  3. Enviar tanto a solução quanto os dados do usuário para o servidor.
  4. Validar a solução e assinatura no servidor.

O aspecto do lado do cliente é gerenciado pelo widget ALTCHA, enquanto a implementação da verificação no lado do servidor é necessária. O manipulador de envio do servidor (por exemplo, POST /form_submit) precisa autenticar o payload do ALTCHA ao enviar o formulário.

Consulte a documentação de prova de trabalho para ler mais sobre o mecanismo por trás do ALTCHA.

Complexidade

Gerar um novo desafio envolve três passagens de computação SHA (uma vez para o desafio e duas vezes para a assinatura HMAC). Da mesma forma, verificar uma solução também requer três passagens.

O intervalo do número aleatório ajusta a dificuldade da tarefa computacional requerida pelo cliente.

Para mais detalhes, consulte ajustando a complexidade.

Servidor

O servidor deve gerar um novo desafio para cada verificação de ALTCHA. Existem dois métodos para fornecer o desafio ao widget:

  1. Usando challengeurl: Se configurado, o widget busca o desafio na URL especificada. O servidor deve retornar um novo desafio conforme descrito abaixo.

  2. Usando challengejson: Forneça diretamente o desafio como uma string codificada em JSON. Este método é útil para páginas renderizadas pelo servidor.

Leia mais sobre o mecanismo de prova de trabalho.

Criando um desafio

Aqui está um exemplo de pseudo-código para criar um desafio no servidor:

// Gerar um sal aleatório (comprimento recomendado: pelo menos 10 caracteres)
salt = random_string();
// Gerar um número secreto aleatório (inteiro positivo)
// O intervalo depende da complexidade escolhida (consulte a documentação)
// Certifique-se de NÃO expor este número ao cliente
secret_number = random_int();
// Calcular o hash SHA256 do salt concatenado com o número_secreto (resultado codificado como string hexadecimal)
challenge = sha2_hex(concat(salt, secret_number));
// Criar uma assinatura do servidor usando uma chave HMAC (resultado codificado como string hexadecimal)
signature = hmac_sha2_hex(challenge, hmac_key);
// Retornar dados codificados em JSON
response = {
algorithm = 'SHA-256',
challenge,
salt,
signature,
};

Parâmetros de Sal

A partir da versão do Widget v0.4 (maio de 2024), é recomendável incluir a bandeira expires e parâmetros adicionais no salt como strings de consulta codificadas em URL. Isso permite passar dados personalizados, que farão parte da assinatura e poderão ser verificados no servidor.

O widget detecta automaticamente o parâmetro expires quando fornecido no sal como um timestamp Unix em segundos:

salt = '<random_salt>?expires=1715526540'

Para garantir a compatibilidade com futuras versões do widget, é recomendável prefixar quaisquer parâmetros personalizados com um sublinhado _.

A biblioteca altcha-lib já suporta parâmetros de sal e verifica automaticamente a expira ção do desafio a partir da versão v0.3.

Envio de formulário

Após submissão dentro de um <form>, o servidor receberá dados codificados como application/x-www-form-urlencoded ou multipart/form-data, dependendo da estrutura do formulário. O payload ALTCHA será incorporado como o campo altcha (customizável via o atributo name no widget).

Use o valor do campo altcha como o payload nos exemplos abaixo. O payload é uma string codificada em Base64-JSON.

Validação de solução

Aqui está um exemplo de pseudo-código para validar uma solução no servidor:

// O payload é uma string codificada BASE64-JSON
// Os dados decodificados são um objeto contendo { algoritmo, desafio, número, sal, assinatura }
data = json_decode(base64_decode(payload));
// Validar algoritmo
alg_ok = equals(data.algorithm, 'SHA-256');
// Validar desafio
challenge_ok = equals(data.challenge, sha2_hex(concat(data.salt, data.number)))
// Validar assinatura
signature_ok = equals(data.signature, hmac_sha2_hex(data.challenge, hmac_key))
// Considerar a solicitação verificada se todas as verificações forem verdadeiras
verified = alg_ok and challenge_ok and signature_ok

Exemplo

A biblioteca JS oficial funciona com Node.js, Bun e Deno.

server.js
import { createChallenge, verifySolution } from 'altcha-lib';
const hmacKey = '$ecret.key'; // Altere a chave HMAC secreta
// Criar um novo desafio e enviá-lo para o cliente:
const challenge = await createChallenge({
hmacKey,
});
// Ao ser enviado, validar o payload:
const ok = await verifySolution(payload, hmacKey);

Para mais exemplos e integrações, consulte a página de Integrações da Comunidade.

Recomendações de Segurança

  • Ataques de Repetição

    Para prevenir a vulnerabilidade de “ataques de repetição”, onde um cliente reenvia a mesma solução várias vezes, o servidor deve implementar medidas que invalidem desafios previamente resolvidos.

    O servidor deve manter um registro de desafios resolvidos e rejeitar quaisquer submissões que tentem reutilizar um desafio que já tenha sido resolvido com sucesso.

  • Expiração de Desafio

    Limitar o período de validade dos desafios pode reforçar as medidas de segurança, garantindo que os desafios não possam ser explorados indefinidamente. Implementar a expiração do desafio envolve definir um limite de tempo no qual um desafio deve ser resolvido e submetido.

    Um método eficaz para alcançar a expiração do desafio envolve incorporar um timestamp do servidor no salt do desafio durante sua geração.

    A partir da versão 0.4 do widget, você pode utilizar parâmetros de sal e incluir o parâmetro ?expires=<unix_ts> no sal. O widget detectará automaticamente o parâmetro expires. Seu servidor deve então verificar a expiração durante o processo de verificação.