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

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

Установка на Debian/Ubuntu

Эти документы относятся к APT пакету nginx-module-hmac-secure-link, предоставляемому репозиторием GetPageSpeed Extras.

  1. Настройте APT репозиторий, как описано в настройке APT репозитория.
  2. Установите модуль:
sudo apt-get update
sudo apt-get install nginx-module-hmac-secure-link
Показать дистрибутивы и архитектуры
| Дистрибутив | Версия             | Компонент   | Архитектуры   |
|-------------|--------------------|-------------|----------------|
| debian      | bookworm           | main        | amd64, arm64   |
| debian      | bookworm-mainline  | main        | amd64, arm64   |
| debian      | trixie             | main        | amd64, arm64   |
| debian      | trixie-mainline    | main        | amd64, arm64   |
| ubuntu      | focal              | main        | amd64, arm64   |
| ubuntu      | focal-mainline     | main        | amd64, arm64   |
| ubuntu      | jammy              | main        | amd64, arm64   |
| ubuntu      | jammy-mainline     | main        | amd64, arm64   |
| ubuntu      | noble              | main        | amd64, arm64   |
| ubuntu      | noble-mainline     | main        | amd64, arm64   |

Описание:

Модуль HMAC secure link для Nginx улучшает безопасность и функциональность стандартного модуля 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 timestamps в 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 затем содержит безопасный токен, который нужно передать на серверный сервер.

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 - Время жизни ссылки, переданной в запросе.