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

session: Библиотека сессий для nginx-module-lua – гибкая и безопасная

Установка

Если вы еще не настроили подписку на RPM-репозиторий, зарегистрируйтесь. Затем вы можете продолжить, выполнив следующие шаги.

CentOS/RHEL 7 или Amazon Linux 2

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 lua-resty-session

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-session

Чтобы использовать эту библиотеку Lua с NGINX, убедитесь, что установлен nginx-module-lua.

В этом документе описывается lua-resty-session v4.2.0, выпущенная 24 августа 2026 года.


lua-resty-session — это безопасная и гибкая библиотека сессий для OpenResty.

TL;DR;

  • Сессии неизменяемы (каждое сохранение создает новую сессию) и не используют блокировки.
  • Данные сессии шифруются с помощью AES-256-GCM с ключом, полученным с использованием HKDF-SHA256 (в FIPS-режиме вместо этого используется PBKDF2 с SHA-256).
  • Сессия имеет заголовок фиксированного размера, который защищен с помощью HMAC-SHA256 MAC с ключом, полученным с использованием HKDF-SHA256 (в FIPS-режиме вместо этого используется PBKDF2 с SHA-256).
  • Данные сессии могут храниться в cookie без сохранения состояния или в различных серверных хранилищах.
  • Один cookie сессии может поддерживать несколько сессий для разных аудиторий.

Примечание: Версия 4.0.0 была переписыванием этой библиотеки с учетом многих уроков, извлеченных за эти годы. Если вы все еще используете более старую версию, обратитесь к старой документации.

Синопсис

worker_processes  1;

events {
  worker_connections 1024;
}

http {
  init_by_lua_block {
    require "resty.session".init({
      remember = true,
      audience = "demo",
      secret   = "RaJKp8UQW1",
      storage  = "cookie",
    })
  }

  server {
    listen       8080;
    server_name  localhost;
    default_type text/html;

    location / {
      content_by_lua_block {
        ngx.say([[
          <html>
          <body>
            <a href=/start>Start the test</a>
          </body>
          </html>
        ]])
      }
    }

    location /start {
      content_by_lua_block {
        local session = require "resty.session".new()
        session:set_subject("OpenResty Fan")
        session:set("quote", "The quick brown fox jumps over the lazy dog")
        local ok, err = session:save()

        ngx.say(string.format([[
          <html>
          <body>
            <p>Session started (%s)</p>
            <p><a href=/started>Check if it really was</a></p>
          </body>
          </html>
        ]], err or "no error"))
      }
    }

    location /started {
      content_by_lua_block {
        local session, err = require "resty.session".start()

        ngx.say(string.format([[
          <html>
          <body>
            <p>Session was started by %s (%s)</p>
            <p><blockquote>%s</blockquote></p>
            <p><a href=/modify>Modify the session</a></p>
          </body>
          </html>
        ]],
          session:get_subject() or "Anonymous",
          err or "no error",
          session:get("quote") or "no quote"
        ))
      }
    }

    location /modify {
      content_by_lua_block {
        local session, err = require "resty.session".start()
        session:set_subject("Lua Fan")
        session:set("quote", "Lorem ipsum dolor sit amet")
        local _, err_save = session:save()

        ngx.say(string.format([[
          <html>
          <body>
            <p>Session was modified (%s)</p>
            <p><a href=/modified>Check if it is modified</a></p>
          </body>
          </html>
        ]], err or err_save or "no error"))
      }
    }

    location /modified {
      content_by_lua_block {
        local session, err = require "resty.session".start()

        ngx.say(string.format([[
          <html>
          <body>
            <p>Session was started by %s (%s)</p>
            <p><blockquote>%s</blockquote></p>
            <p><a href=/destroy>Destroy the session</a></p>
          </body>
          </html>
        ]],
          session:get_subject() or "Anonymous",
          err or "no error",
          session:get("quote")  or "no quote"
        ))
      }
    }

    location /destroy {
      content_by_lua_block {
        local ok, err = require "resty.session".destroy()

        ngx.say(string.format([[
          <html>
          <body>
            <p>Session was destroyed (%s)</p>
            <p><a href=/destroyed>Check that it really was?</a></p>
          </body>
          </html>
        ]], err or "no error"))
      }
    }

    location /destroyed {
      content_by_lua_block {
        local session, err = require "resty.session".open()

        ngx.say(string.format([[
          <html>
          <body>
            <p>Session was really destroyed, you are known as %s (%s)</p>
            <p><a href=/>Start again</a></p>
          </body>
          </html>
        ]],
          session:get_subject() or "Anonymous",
          err or "no error"
        ))
      }
    }
  }
}

Конфигурация

Конфигурацию можно разделить на общую конфигурацию сессии и конфигурацию серверного хранилища.

Вот пример:

init_by_lua_block {
  require "resty.session".init({
    remember = true,
    store_metadata = true,
    secret = "RaJKp8UQW1",
    secret_fallbacks = {
      "X88FuG1AkY",
      "fxWNymIpbb",
    },
    storage = "postgres",
    postgres = {
      username = "my-service",
      password = "kVgIXCE5Hg",
      database = "sessions",
    },
  })
}

Конфигурация сессии

Конфигурация сессии может быть передана в функции инициализации, конструкторы и вспомогательные функции.

Вот возможные параметры конфигурации сессии:

Параметр По умолчанию Описание
secret nil Секрет, используемый для получения ключа. Секрет хешируется с помощью SHA-256 перед использованием. Например, "RaJKp8UQW1".
secret_fallbacks nil Массив секретов, которые можно использовать в качестве альтернативных секретов (при ротации ключей), например, { "6RfrAYYzYq", "MkbTkkyF9C" }.
ikm (случайный) Начальный ключевой материал (или ikm) может быть указан напрямую (без использования секрета) ровно 32 байта данных. Например, "5ixIW4QVMk0dPtoIhn41Eh1I9enP2060"
ikm_fallbacks nil Массив начальных ключевых материалов, которые можно использовать в качестве альтернативных ключей (при ротации ключей), например, { "QvPtlPKxOKdP5MCu1oI3lOEXIVuDckp7" }.
cookie_prefix nil Префикс cookie, используйте nil, "__Host-" или "__Secure-".
cookie_name "session" Имя cookie сессии, например, "session".
cookie_path "/" Путь cookie, например, "/".
cookie_domain nil Домен cookie, например, "example.com"
cookie_http_only true Пометить cookie как HTTP only, используйте true или false.
cookie_secure nil Пометить cookie как secure, используйте nil, true или false.
cookie_priority nil Приоритет cookie, используйте nil, "Low", "Medium" или "High".
cookie_same_site "Lax" Политика same-site для cookie, используйте nil, "Lax", "Strict", "None" или "Default"
cookie_same_party nil Пометить cookie флагом same party, используйте nil, true или false.
cookie_partitioned nil Пометить cookie флагом partitioned, используйте nil, true или false.
remember false Включить или отключить постоянные сессии, используйте nil, true или false.
remember_safety "Medium" Сложность получения ключа для remember cookie, используйте nil, "None" (быстро), "Low", "Medium", "High" или "Very High" (медленно).
remember_cookie_name "remember" Имя cookie постоянной сессии, например, "remember".
audience "default" Аудитория сессии, например, "my-application".
subject nil Субъект сессии, например, "[email protected]".
enforce_same_subject false Если установлено true, аудитории должны иметь одного и того же субъекта. Библиотека удаляет данные аудиторий, не соответствующих субъекту, при сохранении.
stale_ttl 10 Когда сессия сохраняется, создается новая сессия; stale ttl указывает, как долго старая сессия может еще использоваться, например, 10 (в секундах).
idling_timeout 900 Таймаут бездействия указывает, как долго сессия может быть неактивной, пока она не будет считаться недействительной, например, 900 (15 минут) (в секундах), 0 отключает проверки и обновление.
rolling_timeout 3600 Скользящий таймаут указывает, как долго сессия может использоваться, пока ее не нужно продлить, например, 3600 (час) (в секундах), 0 отключает проверки и продление.
absolute_timeout 86400 Абсолютный таймаут ограничивает, как долго сессия может продлеваться, пока не потребуется повторная аутентификация, например, 86400 (день) (в секундах), 0 отключает проверки.
remember_rolling_timeout 604800 Таймаут remember указывает, как долго постоянная сессия считается действительной, например, 604800 (неделя) (в секундах), 0 отключает проверки и продление.
remember_absolute_timeout 2592000 Абсолютный таймаут remember ограничивает, как долго постоянная сессия может продлеваться, пока не потребуется повторная аутентификация, например, 2592000 (30 дней) (в секундах), 0 отключает проверки.
hash_storage_key false Хешировать или нет ключ хранилища. При хешированном ключе хранилища невозможно расшифровать данные на стороне сервера без наличия cookie, используйте nil, true или false.
hash_subject false Хешировать или нет субъект, когда store_metadata включен, например, по причинам PII.
store_metadata false Следует ли также хранить метаданные сессий, например, для сбора данных о сессиях для конкретной аудитории, принадлежащей конкретному субъекту.
touch_threshold 60 Порог touch контролирует, как часто или редко session:refresh обновляет cookie, например, 60 (минута) (в секундах)
compression_threshold 1024 Порог сжатия контролирует, когда данные сжимаются, например, 1024 (килобайт) (в байтах), 0 отключает сжатие.
bind nil Привязать сессию к данным, полученным из HTTP-запроса или соединения, используйте ip, scheme, user-agent. Например, { "scheme", "user-agent" } будет вычислять MAC, также используя схему HTTP-запроса и заголовок User-Agent.
request_headers nil Набор заголовков для отправки на вышестоящий сервер, используйте id, audience, subject, timeout, idling-timeout, rolling-timeout, absolute-timeout. Например, { "id", "timeout" } установит заголовки запроса Session-Id и Session-Timeout, когда вызывается set_headers.
response_headers nil Набор заголовков для отправки клиенту, используйте id, audience, subject, timeout, idling-timeout, rolling-timeout, absolute-timeout. Например, { "id", "timeout" } установит заголовки ответа Session-Id и Session-Timeout, когда вызывается set_headers.
storage nil Хранилище отвечает за хранение данных сессии, используйте nil или "cookie" (данные хранятся в cookie), "dshm", "file", "memcached", "mysql", "postgres", "redis" или "shm", или укажите имя пользовательского модуля ("custom-storage"), или table, реализующую интерфейс хранилища сессий.
revocation nil Хранилище, используемое для записей об отзыве cookie-сессий. Используйте nil или false для отключения, имя хранилища, такое как "shm", "redis", "mysql" или "postgres", имя пользовательского модуля хранилища или table хранилища с методами set/get.
revocation_fail_mode "open" Поведение, когда хранилище отзывов недоступно, используйте "open" (считать не отозванным) или "closed" (отклонить сессию).
dshm nil Конфигурация для хранилища dshm, например, { prefix = "sessions" } (см. ниже)
file nil Конфигурация для файлового хранилища, например, { path = "/tmp", suffix = "session" } (см. ниже)
memcached nil Конфигурация для хранилища memcached, например, { prefix = "sessions" } (см. ниже)
mysql nil Конфигурация для хранилища MySQL / MariaDB, например, { database = "sessions" } (см. ниже)
postgres nil Конфигурация для хранилища Postgres, например, { database = "sessions" } (см. ниже)
redis nil Конфигурация для хранилищ Redis / Redis Sentinel / Redis Cluster, например, { prefix = "sessions" } (см. ниже)
shm nil Конфигурация для хранилища в разделяемой памяти, например, { zone = "sessions" }
["custom-storage"] nil Конфигурация пользовательского хранилища (загружается с помощью require "custom-storage").

При хранении данных в cookie не требуется дополнительная конфигурация, просто установите storage в nil или "cookie".

Конфигурация отзыва сессии

Cookie-сессии (без сохранения состояния) являются самодостаточными: после выдачи cookie остается действительным до истечения срока действия в соответствии с настроенными таймаутами. Отзыв добавляет необязательный список отзыва на основе хранилища, чтобы уничтоженные сессии отклонялись немедленно, не дожидаясь истечения срока действия cookie.

Отзыв доступен только когда данные сессии хранятся в cookie (storage равен nil или "cookie"). Выберите серверную часть явно с помощью revocation = "dshm", "file", "memcached", "mysql", "postgres", "redis" или "shm". Серверная часть использует свою обычную секцию конфигурации и тот же контракт set/get хранилища, который используется для данных сессии. Пользовательские имена модулей хранилища и предварительно созданные таблицы хранилища также поддерживаются. Установка revocation = false или оставление его неустановленным отключает отзыв.

При каждом session:open библиотека проверяет, отозван ли идентификатор сессии. При session:destroy идентификатор записывается в выбранное хранилище с TTL, равным оставшемуся времени жизни сессии (скользящий и абсолютный таймауты). Метка отзыва — это легковесный маркер; никакие данные сессии не сохраняются.

Используйте revocation_fail_mode для управления поведением, когда хранилище недоступно:

  • "open" (по умолчанию): записать предупреждение и считать сессию не отозванной. Уничтожение все равно очищает cookie, даже если запись об отзыве не удалась.
  • "closed": отклонить операцию открытия или уничтожения сессии.

Отзыв применяется к session:destroysession:logout, когда он уничтожает последнюю аудиторию). Он не отзывает предыдущий идентификатор сессии при session:save (ротация сессии) или частичном session:logout (несколько аудиторий). После ротации или частичного выхода из системы предыдущий cookie остается пригодным для использования до истечения stale_ttl или таймаута.

Примеры:

-- Список отзыва в Redis
require("resty.session").init({
  storage = "cookie",
  revocation = "redis",
  redis = {
    host = "127.0.0.1",
    password = "secret",
    prefix = "sessions",
  },
})

-- Список отзыва в разделяемой памяти
require("resty.session").init({
  storage = "cookie",
  revocation = "shm",
  shm = {
    zone = "sessions",
    prefix = "revocations",
  },
})

-- Список отзыва в MySQL
require("resty.session").init({
  storage = "cookie",
  revocation = "mysql",
  mysql = {
    host = "127.0.0.1",
    database = "sessions",
    username = "session",
    password = "secret",
  },
})

Тот же шаблон работает для "dshm", "file", "memcached" и "postgres".

Конфигурация DSHM-хранилища

С хранилищем DSHM вы можете использовать следующие настройки (установите storage в "dshm"):

Параметр По умолчанию Описание
prefix nil Префикс для ключей, хранящихся в DSHM.
suffix nil Суффикс для ключей, хранящихся в DSHM.
host "127.0.0.1" Хост для подключения.
port 4321 Порт для подключения.
connect_timeout nil Управляет значением таймаута по умолчанию, используемым в методе connect объекта TCP/unix-доменного сокета.
send_timeout nil Управляет значением таймаута по умолчанию, используемым в методе send объекта TCP/unix-доменного сокета.
read_timeout nil Управляет значением таймаута по умолчанию, используемым в методе receive объекта TCP/unix-доменного сокета.
keepalive_timeout nil Управляет максимальным временем простоя по умолчанию для соединений в пуле соединений.
pool nil Пользовательское имя для используемого пула соединений.
pool_size nil Размер пула соединений.
backlog nil Размер очереди для использования, когда пул соединений заполнен (настраивается с помощью pool_size).
ssl nil Включить SSL.
ssl_verify nil Проверять сертификат сервера.
server_name nil Имя сервера для нового расширения TLS Server Name Indication (SNI).

Пожалуйста, обратитесь к ngx-distributed-shm, чтобы установить необходимые зависимости.

Конфигурация файлового хранилища

С файловым хранилищем вы можете использовать следующие настройки (установите storage в "file"):

Параметр По умолчанию Описание
prefix nil Префикс файла для файла сессии.
suffix nil Суффикс файла (или расширение без .) для файла сессии.
pool nil Имя пула потоков, в котором происходит запись файла (доступно только на Linux).
path (временная директория) Путь (или директория), в которой создаются файлы сессий.

Реализация требует LuaFileSystem, который вы можете установить с помощью LuaRocks:

 luarocks install LuaFileSystem

Конфигурация Memcached-хранилища

С Memcached вы можете использовать следующие настройки (установите storage в "memcached"):

Параметр По умолчанию Описание
prefix nil Префикс для ключей, хранящихся в memcached.
suffix nil Суффикс для ключей, хранящихся в memcached.
host 127.0.0.1 Хост для подключения.
port 11211 Порт для подключения.
socket nil Файл сокета для подключения.
connect_timeout nil Управляет значением таймаута по умолчанию, используемым в методе connect объекта TCP/unix-доменного сокета.
send_timeout nil Управляет значением таймаута по умолчанию, используемым в методе send объекта TCP/unix-доменного сокета.
read_timeout nil Управляет значением таймаута по умолчанию, используемым в методе receive объекта TCP/unix-доменного сокета.
keepalive_timeout nil Управляет максимальным временем простоя по умолчанию для соединений в пуле соединений.
pool nil Пользовательское имя для используемого пула соединений.
pool_size nil Размер пула соединений.
backlog nil Размер очереди для использования, когда пул соединений заполнен (настраивается с помощью pool_size).
ssl false Включить SSL
ssl_verify nil Проверять сертификат сервера
server_name nil Имя сервера для нового расширения TLS Server Name Indication (SNI).

Конфигурация MySQL / MariaDB-хранилища

С MySQL / MariaDB вы можете использовать следующие настройки (установите storage в "mysql"):

Параметр По умолчанию Описание
host "127.0.0.1" Хост для подключения.
port 3306 Порт для подключения.
socket nil Файл сокета для подключения.
username nil Имя пользователя базы данных для аутентификации.
password nil Пароль для аутентификации, может потребоваться в зависимости от конфигурации сервера.
charset "ascii" Набор символов, используемый в соединении MySQL.
database nil Имя базы данных для подключения.
table_name "sessions" Имя таблицы базы данных, в которой хранятся данные сессии.
table_name_meta "sessions_meta" Имя таблицы метаданных базы данных, в которой хранятся метаданные сессии.
max_packet_size 1048576 Верхний предел для пакетов ответа, отправляемых с сервера MySQL (в байтах).
connect_timeout nil Управляет значением таймаута по умолчанию, используемым в методе connect объекта TCP/unix-доменного сокета.
send_timeout nil Управляет значением таймаута по умолчанию, используемым в методе send объекта TCP/unix-доменного сокета.
read_timeout nil Управляет значением таймаута по умолчанию, используемым в методе receive объекта TCP/unix-доменного сокета.
keepalive_timeout nil Управляет максимальным временем простоя по умолчанию для соединений в пуле соединений.
pool nil Пользовательское имя для используемого пула соединений.
pool_size nil Размер пула соединений.
backlog nil Размер очереди для использования, когда пул соединений заполнен (настраивается с помощью pool_size).
ssl false Включить SSL.
ssl_verify nil Проверять сертификат сервера.

Вам также необходимо создать следующие таблицы в вашей базе данных:

--
-- Таблица базы данных, которая хранит данные сессии.
--
CREATE TABLE IF NOT EXISTS sessions (
  sid  CHAR(43) PRIMARY KEY,
  name VARCHAR(255),
  data MEDIUMTEXT,
  exp  DATETIME,
  INDEX (exp)
) CHARACTER SET ascii;

--
-- Таблица метаданных сессий.
--
-- Это необходимо только если вы хотите хранить метаданные сессий.
--
CREATE TABLE IF NOT EXISTS sessions_meta (
  aud VARCHAR(255),
  sub VARCHAR(255),
  sid CHAR(43),
  PRIMARY KEY (aud, sub, sid),
  CONSTRAINT FOREIGN KEY (sid) REFERENCES sessions(sid) ON DELETE CASCADE ON UPDATE CASCADE
) CHARACTER SET ascii;

Конфигурация Postgres

С Postgres вы можете использовать следующие настройки (установите storage в "postgres"):

Параметр По умолчанию Описание
host "127.0.0.1" Хост для подключения.
port 5432 Порт для подключения.
application 5432 Установить имя соединения, отображаемое в pg_stat_activity (по умолчанию "pgmoon").
username "postgres" Имя пользователя базы данных для аутентификации.
password nil Пароль для аутентификации, может потребоваться в зависимости от конфигурации сервера.
database nil Имя базы данных для подключения.
table_name "sessions" Имя таблицы базы данных, в которой хранятся данные сессии (может быть с префиксом схема базы данных).
table_name_meta "sessions_meta" Имя таблицы метаданных базы данных, в которой хранятся метаданные сессии (может быть с префиксом схема базы данных).
connect_timeout nil Управляет значением таймаута по умолчанию, используемым в методе connect объекта TCP/unix-доменного сокета.
send_timeout nil Управляет значением таймаута по умолчанию, используемым в методе send объекта TCP/unix-доменного сокета.
read_timeout nil Управляет значением таймаута по умолчанию, используемым в методе receive объекта TCP/unix-доменного сокета.
keepalive_timeout nil Управляет максимальным временем простоя по умолчанию для соединений в пуле соединений.
pool nil Пользовательское имя для используемого пула соединений.
pool_size nil Размер пула соединений