Перейти к содержанию

hmac-secure-link: Альтернативный модуль NGINX HMAC Secure Link с поддержкой хешей OpenSSL

Установка

Вы можете установить этот модуль в любом дистрибутиве на базе RHEL, включая, но не ограничиваясь:

  • RedHat Enterprise Linux 7, 8, 9 и 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 и Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-hmac-secure-link
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-hmac-secure-link

Включите модуль, добавив следующее в начало файла /etc/nginx/nginx.conf:

load_module modules/ngx_http_hmac_secure_link_module.so;

Этот документ описывает nginx-module-hmac-secure-link v0.3, выпущенный 6 марта 2019 года.


Описание:

Модуль Nginx HMAC secure link улучшает безопасность и функциональность стандартного модуля secure link.
Безопасный токен создается с использованием безопасной конструкции HMAC с произвольным алгоритмом хеширования, поддерживаемым OpenSSL, например: blake2b512, blake2s256, gost, md4, md5, rmd160, sha1, sha224, sha256, sha3-224, sha3-256, sha3-384, sha3-512, sha384, sha512, sha512-224, sha512-256, shake128, shake256, sm3.

Кроме того, безопасный токен создается, как описано в RFC2104, а именно, H(secret_key XOR opad,H(secret_key XOR ipad, message)), вместо простого MD5(secret_key,message, expire).

Использование:

Сообщение, которое нужно захешировать, определяется с помощью secure_link_hmac_message, secret_key задается с помощью secure_link_hmac_secret, а алгоритм хеширования H определяется с помощью secure_link_hmac_algorithm.

Для повышения безопасности к сообщению, которое нужно захешировать, следует добавить временную метку в формате ISO 8601 2017-12-08T07:54:59+00:00 (один из вариантов в соответствии с ISO 8601) или в виде Unix Timestamp.

Возможно создание ссылок с ограниченным сроком действия. Это определяется необязательным параметром. Если период истечения равен нулю или не указан, ссылка имеет неограниченный срок действия.

Пример конфигурации для серверной стороны.

location ^~ /files/ {
    # Переменные, которые будут переданы: безопасный токен, временная метка, срок действия (необязательно)
    secure_link_hmac  $arg_st,$arg_ts,$arg_e;

    # Секретный ключ
    secure_link_hmac_secret my_secret_key;

    # Сообщение для проверки
    secure_link_hmac_message $uri$arg_ts$arg_e;

    # Криптографическая хеш-функция для использования
    secure_link_hmac_algorithm sha256;

    # Если хеш неверен, то $secure_link_hmac - это пустая строка.
    # Если хеш верен, но ссылка уже истекла, то $secure_link_hmac равен нулю.
    # Если хеш верен и ссылка не истекла, то $secure_link_hmac равен единице.

    # В производственной среде мы не должны раскрывать потенциальному злоумышленнику
    # причину, по которой аутентификация hmac не удалась
    if ($secure_link_hmac != "1") {
        return 404;
    }

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

Сторона приложения должна использовать стандартную функцию hash_hmac для генерации хеша, который затем необходимо закодировать в base64url. Пример на Perl ниже.

Переменная $data содержит безопасный токен, временную метку в формате ISO 8601 и срок действия в секундах

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

        my $now = time();
        my $key = "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;
        my $digest = hmac_sha256_base64($data . $timestamp . $expire,  $key);
        $digest =~ tr(+/)(-_);
        $data = "st=" . $digest . "&ts=" . $timestamp . "&e=" . $expire;
        return $data;
    }
';

Аналогичная функция на PHP

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

Использование Unix timestamp в 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}`;
const hashmac = crypto.createHmac('sha256', secret).update(stringToSign).digest('base64')
      .replace(/=/g, '')
      .replace(/\+/g, '-')
      .replace(/\//g, '_');
const loc = `https://host/files/top_secret.pdf?st=${hashmac}&ts=${unixTimestamp}&e=${expire}`;

Также возможно использовать этот модуль с Nginx, действующим как прокси-сервер.

Строка, которую нужно подписать, определяется в secure_link_hmac_message, переменная secure_link_hmac_token затем содержит безопасный токен, который будет передан на сервер backend.

location ^~ /backend_location/ {
    set $expire 60;

    secure_link_hmac_message "$uri$time_iso8601$expire";
    secure_link_hmac_secret "my_very_secret_key";
    secure_link_hmac_algorithm sha256;

    proxy_pass "http://backend_server$uri?st=$secure_link_hmac_token&ts=$time_iso8601&e=$expire";
}

Встроенные переменные

  • $secure_link_hmac -
  • $secure_link_hmac_token -
  • $secure_link_hmac_expires - Срок действия ссылки, переданный в запросе.

GitHub

Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-hmac-secure-link.