Saltar a contenido

auth-hash: Autenticación de enlace seguro mediante hash

Instalación

Puedes instalar este módulo en cualquier distribución basada en RHEL, incluyendo, pero no limitado a:

  • RedHat Enterprise Linux 7, 8, 9 y 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 y 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

Habilita el módulo añadiendo lo siguiente en la parte superior de /etc/nginx/nginx.conf:

load_module modules/ngx_http_auth_hash_module.so;

Este documento describe nginx-module-auth-hash v0.1.0 lanzado el 06 de enero de 2026.


Descripción:

El módulo de enlace seguro HASH de Nginx mejora la seguridad y funcionalidad del módulo de enlace seguro estándar. Se crea un token seguro utilizando una construcción de HASH seguro con un algoritmo de hash arbitrario soportado por OpenSSL, por ejemplo: 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:

El mensaje a ser hasheado se define por auth_hash_message, secret_key se proporciona mediante auth_hash_secret, y el algoritmo de hash H se define por auth_hash_algorithm.

Para mejorar la seguridad, el tiempo o una marca de tiempo (dependiendo del formato de fecha especificado por el parámetro de formato) debe ser añadido al mensaje a ser hasheado.

Es posible crear enlaces con una vida útil limitada. Esto se define mediante los parámetros opcionales range_start o range_end. Si el período de expiración no se especifica, un enlace tiene una vida útil ilimitada.

Ejemplo de configuración para el lado del servidor.

location ^~ /files/ {
    # Habilita la función, si está deshabilitada, $auth_hash siempre estará vacío
    auth_hash on;

    # Establece el valor de tiempo utilizado para la verificación.
    # Puedes establecer el rango de tiempo de expiración, el formato del valor de tiempo y la zona horaria del valor de tiempo
    auth_hash_check_time $arg_ts range_end=$arg_e format=%s;

    # Establece el valor del token utilizado para la verificación
    # Los formatos disponibles son hex (predeterminado), base64, base64url y bin
    auth_hash_check_token $arg_st format=hex;

    # Clave secreta
    auth_hash_secret "my_secret_key";

    # Mensaje a ser verificado
    auth_hash_message "$uri|$arg_ts|$arg_e|$auth_hash_secret";

    # Función hash criptográfica a ser utilizada
    auth_hash_algorithm sha256;

    # En un entorno de producción, no debemos revelar al posible atacante
    # por qué ha fallado la autenticación por hash
    # - Si el hash es incorrecto, entonces $auth_hash es una cadena NULL.
    # - Si el hash es correcto y el enlace no ha expirado, entonces $auth_hash es "1".
    if ($auth_hash != "1") {
        return 403;
    }

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

El lado de la aplicación debe usar una función hash estándar para generar el hash, que luego necesita ser codificado en hex o base64url. Ejemplo en Perl a continuación.

La variable $data contiene el token seguro, la marca de tiempo en formato ISO 8601 y el período de expiración en 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;
    }
';

Una función similar en 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 la marca de tiempo Unix en 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}`;

Versión en 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"

Variables Embebidas

  • $auth_hash - Si el hash es correcto y el enlace no ha expirado, entonces $auth_hash es "1". De lo contrario, es nulo.
  • $auth_hash_secret - El valor de la directiva auth_hash_secret

GitHub

Puedes encontrar consejos adicionales de configuración y documentación para este módulo en el repositorio de GitHub para nginx-module-auth-hash.