
Аутентификация в NestJS: доступ, обновление токенов и прекращение сеансов
- NestJS authentication
- access token
- refresh token
- token rotation
- session revocation
- JWT security
- logout all devices

Аутентификация в NestJS: доступ, обновление токенов и прекращение сеансов
Аутентификация в рабочем продукте — это система безопасности с полным жизненным циклом, а не контроллер, который лишь подписывает JWT. Она должна ограничивать пользу украденных учетных данных, различать сеансы и устройства, правильно обрабатывать одновременные обновления, прекращать длительный доступ после выхода или взлома, защищать браузерные сценарии, заменять ключи, сохранять доказательства для аудита и безопасно вести себя при недоступности базы данных или поставщика идентификации.
В практической системе для собственных клиентов краткосрочные и длительные полномочия следует разделять. Подписанный токен доступа с малым сроком действия подтверждает заявленные сведения для API без обращения к хранилищу сеансов при каждом обычном запросе. Случайный секрет с высокой энтропией позволяет продолжить один серверный сеанс и заменяется после каждого использования. Окончательным источником истины для длительного доступа остается база данных, а срок действия токена доступа определяет наибольшую обычную задержку, с которой отзыв распространится на конечные точки без состояния.
Эта модель подходит не всем. Зрелый поставщик OpenID Connect может быть безопаснее самостоятельной поддержки паролей и восстановления доступа. Для рискованных операций могут потребоваться недавняя повторная аутентификация, MFA, отдельное разрешение на конкретную операцию или проверка действующего сеанса. Мобильные, браузерные, машинные и партнерские клиенты располагают разными возможностями хранения секретов и привязки их к отправителю. Начинайте с модели угроз: кража учетных данных, XSS, CSRF, утечка базы данных, повторное использование токена, выявление существования учетной записи, фиксация сеанса, внутренний злоумышленник, компрометация ключа и отказ в обслуживании.
Прежде чем выбирать сроки действия токенов, опишите ожидаемые результаты: какие действия нужно блокировать немедленно, как пользователь просматривает и завершает сеансы, что именно отзывает сброс пароля, отделены ли ключи API, при каких условиях служба поддержки может действовать от имени пользователя, какие события вызывают оповещения и какие доказательства нужны специалистам во время происшествия. Наши услуги по разработке на NestJS помогают приспособить эти средства контроля к клиентам, рискам, нормативным требованиям и эксплуатационным возможностям конкретного продукта.
Установите границы доверия к личности и токену
Вход начинается на недоверенной границе системы. Проверяйте DTO во время выполнения, осторожно нормализуйте идентификаторы, ограничивайте частоту запросов по нескольким обоснованным признакам и формируйте ответы так, чтобы они не раскрывали существование учетной записи. Пароли проверяйте современной функцией хеширования с настроенной стоимостью вычислений, а затем применяйте правила состояния учетной записи, подтвержденных каналов, MFA, риска и восстановления. Создавайте сеанс лишь после успеха всех обязательных факторов; идентификатор предварительного сеанса обязательно замените, чтобы предотвратить его фиксацию.
Токен доступа выпускайте с явно заданным алгоритмом подписи и управляемым ключом. Проверка должна ограничивать алгоритм, ключ и подпись, издателя, получателя, срок действия, время начала действия, если оно указано, тип токена и обязательные поля; простое декодирование ничего не подтверждает. Набор данных внутри должен быть минимальным: субъект, идентификатор сеанса или семейства, идентификатор токена, издатель, получатель, время выпуска и окончания действия, а также лишь те сведения о правах, которым безопасно оставаться неизменными в течение этого короткого срока. Аутентификация определяет личность, но защитники NestJS и прикладная логика все равно должны разрешить конкретную операцию над конкретным ресурсом.
Владельца ключей и порядок их замены определите с самого начала. Симметричная подпись уместна при единой границе между издателем и проверяющим; асимметричные ключи упрощают независимую проверку и ограниченное распространение секретных данных. Закрытые и общие секреты храните в специализированном хранилище, добавляйте идентификатор ключа, когда это требуется, и публикуйте только предназначенные для проверки ключи. Старый и новый ключи принимайте одновременно в течение документированного переходного периода, а неизвестные алгоритмы и ключи отклоняйте. Инструкция на случай срочной компрометации должна называть ответственного за замену, способ обновления всех проверяющих, перечень недействительных сеансов или токенов и порядок оповещения клиентов.
Управляйте обновлением как серверным сеансом
Длительный доступ представляйте как серверный сеанс или семейство токенов. Создайте непрозрачный секрет обновления из криптографически надежного источника случайности, верните его клиенту лишь один раз, а в базе храните только хеш с секретным ключом. Тогда утечка базы данных не превратит записи в готовые учетные данные. Сохраняйте пользователя, семейство, текущий токен, время создания и последнего использования, срок бездействия и окончательный срок, ссылку на преемника, время и причину отзыва, уровень аутентификации и минимальные сведения об устройстве. При каждой замене наследуйте первоначальный окончательный срок, чтобы активность не продлевала доступ бесконечно.
В браузере секрет обновления обычно следует передавать в файле cookie с подходящей областью действия и признаками Secure и HttpOnly: обычный JavaScript не сможет его прочитать. Значение SameSite выбирайте в соответствии с настоящей схемой входа и размещения приложения; по возможности сужайте Path и Domain, обязательно используйте HTTPS и защищайте от CSRF каждый изменяющий состояние запрос, который опирается на cookie. HttpOnly не устраняет XSS: внедренный код все еще может выполнять действия через браузер. Не помещайте токены в адреса или журналы, а для чувствительных ответов установите подходящие правила кеширования.
Мобильным и настольным клиентам требуются защищенное средствами платформы хранилище и модель угроз для общедоступного клиента. Конфиденциальный серверный клиент может аутентифицировать себя, тогда как распространяемое среди пользователей приложение не способно надежно хранить общий секрет. Если протокол и клиент это поддерживают, рассмотрите привязку учетных данных к отправителю. Название устройства, сведения о клиентской программе, IP-адрес и географическое положение помогают пользователю узнать активность и полезны для оценки риска, однако это изменчивые сигналы, а не доказательство личности. Не блокируйте доступ автоматически из-за обычных поездок, сетей операторов, служб сокрытия адреса или обновлений программ.
CREATE TABLE auth_session (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
family_id UUID NOT NULL,
refresh_token_digest CHAR(64) NOT NULL UNIQUE,
replaced_by_session_id UUID NULL,
created_at TIMESTAMPTZ NOT NULL,
last_used_at TIMESTAMPTZ NOT NULL,
idle_expires_at TIMESTAMPTZ NOT NULL,
absolute_expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ NULL,
revoke_reason VARCHAR(64) NULL,
CONSTRAINT auth_session_replacement_fk
FOREIGN KEY (replaced_by_session_id) REFERENCES auth_session(id)
);
CREATE INDEX auth_session_user_active_idx
ON auth_session (user_id, revoked_at);
CREATE INDEX auth_session_family_idx
ON auth_session (family_id);Заменяйте токены неделимо, а повторное использование считайте угрозой
Каждые принятые учетные данные обновления должны стать непригодными и породить ровно одного преемника в том же семействе. Поиск хеша, проверку сроков и отзыва, аннулирование старого токена, создание нового и связывание обеих записей выполняйте в одной транзакции базы данных с блокировкой строки или условной записью. Иначе два одновременных запроса могут принять один и тот же секрет и создать две активные ветви. Установите ограничение уникальности в соответствии с моделью, а в клиенте объединяйте параллельные попытки обновления, чтобы каждый неудачный запрос к API не запускал собственную замену.
Повторное появление уже замененного токена может означать компрометацию. RFC 9700 описывает последовательную замену как способ обнаружения повторного использования, поскольку сервер авторизации хранит связь между прежним и новым токенами. Сервер не способен надежно определить, кто воспользовался секретом первым — законный клиент или злоумышленник. Отзовите действующее семейство, отклоните последующие обновления, запишите событие безопасности без самого секрета и потребуйте нового входа. Пользователя или команду безопасности оповещайте в соответствии с риском и правилами продукта.
Ненадежная сеть создает неоднозначность: сервер мог завершить замену, а ответ — потеряться. Узкий и тщательно проанализированный льготный механизм иногда улучшает удобство, но свободный прием старого токена уничтожает защиту от повторного использования. Прежде чем разрешать исключение, опишите автомат состояний и его неизменные правила: наибольшее число использований, временной промежуток, доказательство того же клиента, восстановление ответа и реакцию на второе предъявление. Отзыв должен сохраняться даже при возврате ошибки: если исключение внутри транзакции отменяет аннулирование семейства, это незаметный, но серьезный изъян реализации.
async rotate(presented: string): Promise<TokenPair> {
const digest = this.tokenDigest(presented);
const outcome = await this.dataSource.transaction(async (manager) => {
const current = await manager.findOne(AuthSession, {
where: { refreshTokenDigest: digest },
lock: { mode: 'pessimistic_write' },
});
if (!current || this.isExpired(current)) {
throw new UnauthorizedException();
}
if (current.replacedBySessionId) {
await this.revokeFamily(manager, current.familyId, 'refresh_reuse');
return { kind: 'reused' } as const;
}
if (current.revokedAt) throw new UnauthorizedException();
const rawNext = randomBytes(32).toString('base64url');
const next = manager.create(AuthSession, {
id: randomUUID(),
userId: current.userId,
familyId: current.familyId,
refreshTokenDigest: this.tokenDigest(rawNext),
createdAt: new Date(),
lastUsedAt: new Date(),
idleExpiresAt: this.nextIdleExpiry(),
absoluteExpiresAt: current.absoluteExpiresAt,
});
await manager.save(next);
current.replacedBySessionId = next.id;
current.lastUsedAt = new Date();
await manager.save(current);
return { kind: 'rotated', userId: current.userId, next, rawNext } as const;
});
// Throw after commit so replay-triggered family revocation survives.
if (outcome.kind === 'reused') throw new UnauthorizedException();
return this.issuePair(outcome.userId, outcome.next.id, outcome.rawNext);
}Четко определите последствия отзыва
Разные операции следует определить отдельно. «Выйти на этом устройстве» означает отозвать текущий сеанс или семейство и удалить браузерный cookie с теми же Path, Domain, Secure и SameSite и надлежащим сроком окончания. Операция должна быть идемпотентной: повторный запрос не восстанавливает сеанс и не раскрывает его состояние. «Выйти на всех устройствах» отзывает все подходящие сеансы учетной записи в рамках одной контролируемой операции. Дайте пользователю возможность просматривать недавние сеансы и завершать выбранный, но не считайте показанные сведения об устройстве доказательством личности.
Сброс пароля, подтвержденный захват учетной записи, ее отключение, удаление фактора аутентификации, действие администратора или рискованная замена учетных данных могут потребовать более широкого отзыва и недавней повторной аутентификации. Отдельно решите судьбу ключей API, делегированных разрешений, доверенных устройств, кодов восстановления и партнерских сеансов. Очистка хранилища на клиенте не является отзывом: рекомендации OWASP требуют аннулирования на сервере. Для чувствительных страниц предусмотрите заголовки кеширования и очистку браузерных данных, но не подменяйте этим решение сервера.
Самодостаточный JWT доступа может оставаться действующим до окончания срока. Если бизнесу требуется немедленная блокировка, на чувствительных границах проверяйте текущее состояние сеанса или версию безопасности пользователя либо ведите краткосрочный кеш отзывов. Такой выбор намеренно добавляет состояние, задержку и зависимость от доступности, поэтому заранее опишите поведение при сбое: разрешать или запрещать запрос. Другой вариант — еще более короткий срок токена доступа и дополнительная проверка для важных действий. Решение должно опираться на цену потерь и модель угроз, а не на заимствованную «универсальную» продолжительность.
Проверяйте враждебные и одновременные сценарии
Проверяйте токены как враждебные входные данные. Охватите неправильное строение, чрезмерные заголовки, ложные подписи, попытки подмены алгоритма, неизвестные идентификаторы ключей, неправильного издателя или получателя, просроченное и еще не действующее время, отсутствие обязательных полей, неверный тип токена, отозванные сеансы, истечение срока бездействия и окончательного срока, отключение пользователя и попытку доступа к чужой организации или записи. Убедитесь, что средства декодирования нигде не подменяют аутентификацию, а HTTP, GraphQL, WebSocket и обмен сообщениями, если он есть, применяют одинаковые правила.
Отдельно проверьте одновременность и частичные отказы. Отправьте одни и те же учетные данные обновления параллельно и докажите, что действующим остается только один преемник. Повторите уже замененный токен и убедитесь, что отзыв семейства не отменяется. Смоделируйте потерю ответа о замене, повторный выход, состязание выхода с обновлением, замену ключей под нагрузкой, недоступность базы сеансов, исчерпание ограничения запросов и повтор после истечения времени ожидания. Проверьте удаление cookie, CORS, отклонение CSRF, кеширование, допустимое расхождение часов и доступные для восприятия сообщения клиента.
Телеметрия аутентификации должна уважать частную жизнь. Измеряйте неудачные входы, результаты обновления, обнаруженное повторное использование, отзывы, неудачи MFA, создание сеансов, ошибки проверки ключей и задержку, но не записывайте пароли, исходные токены, ссылки сброса, секреты или лишние персональные данные. Защитите аудиторские записи от подмены и ограничьте доступ к ним. Каждому оповещению нужны ответственный и инструкция реагирования; слабые признаки, такие как смена IP-адреса или клиентской программы, должны помогать расследованию, а не автоматически доказывать взлом.
Проведите учения для разных компрометаций: утечка ключа подписи, раскрытие базы токенов обновления, вредоносная зависимость, украденное устройство, массовый перебор украденных паролей и сбой поставщика идентификации. План реагирования должен определять локализацию угрозы, замену ключей и прекращение сеансов, оповещение клиентов, сохранение доказательств, восстановление и изменения после происшествия. Аутентификация готова к рабочей среде только тогда, когда ее отказы спроектированы и проверены так же тщательно, как успешный вход.
Проверка аутентификации перед запуском
- Проверенный доступ: у токенов доступа короткий и обоснованный срок; до выдачи разрешения проверяются алгоритм, ключ, подпись, издатель, получатель, время, тип и обязательные поля.
- Защищенное обновление: учетные данные обновления являются секретами с высокой энтропией, защищаются при передаче и хранении на клиенте, никогда не попадают в адреса или журналы, а в базе существуют только как хеши с секретным ключом.
- Неделимая замена: одна транзакция поглощает предъявленный токен, создает единственного преемника, сохраняет окончательный срок и историю семейства, чтобы повторное использование приводило к отзыву действующей ветви.
- Однозначный отзыв: выход на одном или всех устройствах, сброс пароля, захват либо отключение учетной записи, действие администратора, ключи API и задержка недействительности JWT доступа имеют документированные последствия.
- Защищенная граница браузера: атрибуты cookie, доверенные источники, CORS, защита от CSRF, CSP, правила кеширования, противодействие XSS и очистка после выхода соответствуют настоящей схеме развертывания, а не исходным местным настройкам.
- Управляемая безопасность: замена ключей, телеметрия без секретов, ограничение частоты, защита аудита, учения по восстановлению, ответственные за оповещения, реагирование на компрометацию и обновление зависимостей являются проверенными обязанностями.
Стоит ли делать токен обновления в формате JWT?
Какой срок действия выбрать для доступа и обновления?
Устраняет ли cookie с HttpOnly риски XSS и CSRF?
Может ли выход немедленно сделать JWT доступа недействительным?
Опишите клиентов, способы установления личности, хранение токенов, модель сеансов, чувствительные операции, нормативные ограничения и сценарии происшествий. Мы найдем конкретные пробелы и определим соразмерные правила замены и отзыва, защиты браузера, телеметрии и восстановления.
Наши исследования
Исследование и разработка решений на основе искусственного интеллекта для оптимизации бизнес-процессов и повышения эффективности принятия решений.
Анализ моделей машинного обучения для прогнозной аналитики в сфере финансов, электронной коммерции и SaaS-платформ.
Исследование технологий обработки естественного языка и компьютерного зрения для усиления автоматизации, персонализации и поддержки клиентов.


