Pular para conteúdo

auth-hash: Autenticação de hash de link seguro

Instalação

Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:

  • RedHat Enterprise Linux 7, 8, 9 e 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 e Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-auth-hash
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-auth-hash

Ative o módulo adicionando o seguinte no topo de /etc/nginx/nginx.conf:

load_module modules/ngx_http_auth_hash_module.so;

Este documento descreve o nginx-module-auth-hash v0.1.0 lançado em 06 de janeiro de 2026.


Descrição:

O módulo de link seguro HASH do Nginx melhora a segurança e a funcionalidade do módulo de link seguro padrão. Um token seguro é criado usando uma construção de HASH segura com um algoritmo de hash arbitrário suportado pelo OpenSSL, por exemplo: blake2b512, blake2s256, gost, md4, md5, mdc2, rmd160, sha1, sha224, sha256, sha3-224, sha3-256, sha3-384, sha3-512, sha384, sha512, sha512-224, sha512-256, shake128, shake256, sm3.

Uso:

A mensagem a ser hasheada é definida por auth_hash_message, secret_key é fornecida por auth_hash_secret, e o algoritmo de hash H é definido por auth_hash_algorithm.

Para melhorar a segurança, o tempo ou um timestamp (dependendo do formato de data especificado pelo parâmetro de formato) deve ser anexado à mensagem a ser hasheada.

É possível criar links com tempo de vida limitado. Isso é definido pelos parâmetros opcionais range_start ou range_end. Se o período de expiração não for especificado, um link terá tempo de vida ilimitado.

Exemplo de configuração para o lado do servidor.

location ^~ /files/ {
    # Habilita o recurso, se desativado, $auth_hash sempre estará vazio
    auth_hash on;

    # Define o valor de tempo usado para verificação.
    # Você pode definir o intervalo de tempo de expiração, o formato do valor de tempo e o fuso horário do valor de tempo
    auth_hash_check_time $arg_ts range_end=$arg_e format=%s;

    # Define o valor do token usado para verificação
    # Os formatos disponíveis são hex (padrão), base64, base64url e bin
    auth_hash_check_token $arg_st format=hex;

    # Chave secreta
    auth_hash_secret "my_secret_key";

    # Mensagem a ser verificada
    auth_hash_message "$uri|$arg_ts|$arg_e|$auth_hash_secret";

    # Função de hash criptográfico a ser usada
    auth_hash_algorithm sha256;

    # Em ambiente de produção, não devemos revelar ao potencial atacante
    # por que a autenticação de hash falhou
    # - Se o hash estiver incorreto, então $auth_hash é uma string NULL.
    # - Se o hash estiver correto e o link não tiver expirado, então $auth_hash é "1".
    if ($auth_hash != "1") {
        return 403;
    }

    rewrite ^/files/(.*)$ /files/$1 break;
}

O lado da aplicação deve usar uma função de hash padrão para gerar o hash, que então precisa ser codificado em hex ou base64url. Exemplo em Perl abaixo.

A variável $data contém o token seguro, timestamp no formato ISO 8601 e o período de expiração em segundos

perl_set $secure_token '
    sub {
        use Digest::SHA qw(sha256_base64);
        use POSIX qw(strftime);

        my $now = time();
        my $secret = "my_very_secret_key";
        my $expire = 60;
        my $tz = strftime("%z", localtime($now));
        $tz =~ s/(\d{2})(\d{2})/$1:$2/;
        my $timestamp = strftime("%Y-%m-%dT%H:%M:%S", localtime($now)) . $tz;
        my $r = shift;
        my $data = $r->uri;

        # hex
        my $string_to_hash = $data . "|" . $timestamp . "|" . $expire . "|" . $secret;
        my $digest_binary = sha256($string_to_hash);
        my $digest = unpack("H*", $digest_binary);

        # base64url
        # my $digest = sha256_base64($data . "|" . $timestamp . "|" . $expire . "|" . $secret);
        # $digest =~ tr/+/_/;
        # $digest =~ s/=+$//;

        $data = "st=" . $digest . "&ts=" . $timestamp . "&e=" . $expire;
        return $data;
    }
';

Uma função semelhante em PHP

$secret = 'my_very_secret_key';
$expire = 60;
$algo = 'sha256';
$timestamp = date('c');
$unixtimestamp = time();
$stringtosign = "/files/top_secret.pdf|{$unixtimestamp}|{$expire}|{$secret}";
// hex
$hash = bin2hex(hash($algo, $stringtosign, true));
// base64url
// $hash = base64_encode(hash($algo, $stringtosign, true));
// $hash = strtr($hash, '+/', '-_');
// $hash = str_replace('=', '', $hash);
$host = $_SERVER['HTTP_HOST'];
$loc = "https://{$host}/files/top_secret.pdf?st={$hash}&ts={$unixtimestamp}&e={$expire}";

Usando timestamp Unix em Node.js

const crypto = require("crypto");
const secret = 'my_very_secret_key';
const expire = 60;
const unixTimestamp = Math.round(Date.now() / 1000.);
const stringToSign = `/files/top_secret.pdf|${unixTimestamp}|${expire}|${secret}`;
// hex
const hash = crypto.createHash('sha256').update(stringToSign).digest('hex')
// base64url
// const hash = crypto.createHash('sha256').update(stringToSign).digest('base64')
//       .replace(/=/g, '')
//       .replace(/\+/g, '-')
//       .replace(/\//g, '_');
const loc = `https://host/files/top_secret.pdf?st=${hash}&ts=${unixTimestamp}&e=${expire}`;

Versão Bash

#!/bin/bash

SECRET="my_super_secret"
TIME_STAMP="$(date -d "today + 0 minutes" +%s)";
EXPIRES="3600"; # segundos
URL="/file/my_secret_file.txt"
ST="$URL|$TIME_STAMP|$EXPIRES|$SECRET"
## hex
TOKEN="$(echo -n $ST | openssl dgst -sha256 | awk '{print $1}')"
## Base64url
## TOKEN="$(echo -n $ST | openssl dgst -sha256 -binary | openssl base64 | tr +/ -_ | tr -d =)"

echo "http://127.0.0.1$URL?st=$TOKEN&ts=$TIME_STAMP&e=$EXPIRES"

Variáveis Embutidas

  • $auth_hash - Se o hash estiver correto e o link não tiver expirado, então $auth_hash é "1". Caso contrário, é nulo.
  • $auth_hash_secret - O valor da diretiva auth_hash_secret

GitHub

Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório GitHub do nginx-module-auth-hash.