Express / 38 минут

Сессии, права и безопасный ввод

Разделите идентификацию, проверку прав, ограничения ввода и защиту cookie-запросов.

В процессе Теория: впереди Практика: впереди Тест: впереди
11 / 12
После этой главы
  • Разделите идентификацию, проверку прав, ограничения ввода и защиту cookie-запросов.
  • Применить тему в задаче «Сессии, права и безопасный ввод» и объяснить граничные случаи.

Около 8 минут на чтение и разбор примеров. Практика — отдельно, в своём темпе.

Разные вопросы на границе запроса

Валидация отвечает, подходит ли форма данных. Аутентификация устанавливает подтверждённого пользователя. Авторизация решает, разрешено ли ему действие над конкретным ресурсом. Эти проверки связаны порядком сценария, но не заменяют друг друга. Правильно сформированное поле role='admin' из клиентского JSON не является доказательством административных прав.

Сервер не должен доверять интерфейсной кнопке, localStorage или обычному произвольному заголовку с userId. Любой клиент может изменить их. Подтверждённая личность должна поступать из проверенного механизма сессии или токена. Для production используют поддерживаемые библиотеки и согласованные правила проверки, а не собственную криптографию.

Сессия и cookie

Cookie может автоматически отправляться браузером вместе с подходящим запросом. Флаг HttpOnly ограничивает её чтение скриптами страницы, Secure относится к HTTPS, SameSite влияет на межсайтовую отправку. Эти параметры полезны, но каждый решает свою задачу. Не включайте Secure на локальном HTTP без соответствующего окружения, иначе ожидаемая сессия может не работать.

Серверная сессия обычно имеет ограниченный срок жизни, возможность отзыва и непрозрачный случайный идентификатор. Постоянные credentials и пароли не отправляют обратно клиенту. Успешный вход не освобождает последующие маршруты от проверки актуальности сессии. Выход должен отзывать соответствующее состояние, а не только очищать надпись в интерфейсе.

Проверка прав на ресурс

После установления пользователя проверяют владельца заметки, роль или другое правило. Одной общей проверки «вошёл в систему» недостаточно, если ресурс принадлежит другому человеку. Политика должна исполняться для чтения, изменения и удаления, где это требуется. Прямой запрос к соседнему id должен проходить те же серверные правила, что и запрос из вашего интерфейса.

JavaScript
function canEdit(actor, note) {
  return actor !== null
    && (actor.role === 'admin' || actor.id === note.ownerId);
}

actor в таком правиле — уже подтверждённая сервером модель, а не невалидированный body. Политика не должна создавать этот факт сама из произвольной строки. Отдельно определите, какие поля пользователя действительно входят в доверенный контекст и когда они обновляются после изменения прав.

CSRF и CORS

При cookie-аутентификации браузер может автоматически прикладывать сессию к запросу. Поэтому изменяющие действия нуждаются в подходящей CSRF-защите: проверке ожидаемого происхождения, токене или специальном проверяемом механизме в рамках выбранной архитектуры. SameSite помогает, но не должен рассматриваться как единственная универсальная защита всех сценариев.

CORS управляет браузерным доступом к ответу другого origin. Он не запрещает прямые HTTP-запросы небраузерного клиента и не заменяет проверку прав. Не решайте ошибку разработки разрешением любого Origin с credentials. Используйте точный согласованный allowlist и настройку proxy с пониманием, какие заголовки доверены инфраструктуре.

JavaScript
function checkOrigin(req, allowedOrigin) {
  return req.get('origin') === allowedOrigin;
}

Эта небольшая функция показывает только одну проверку происхождения, а не готовую полную систему авторизации. Правила отсутствующего Origin и типов клиентов нужно определить для конкретного API, а не копировать без анализа. Доверие к forwarded-заголовкам тоже должно соответствовать реальной цепочке proxy.

Ограничения, зависимости и логи

Ограничивайте размер body, длину строк, число элементов, частоту чувствительных действий и время внешних операций. Не передавайте пользовательские пути в файловую систему и произвольные URL в серверный fetch без специальной ограничивающей модели. Для SQL используйте параметризованный API. Успешная проверка string не делает значение безопасным во всех контекстах использования.

JavaScript
app.disable('x-powered-by');
app.use(express.json({ limit: '16kb' }));

Защитные заголовки и обновления зависимостей дополняют эти правила. Логи не должны содержать пароли, cookies и полные чувствительные DTO. Неожиданные ошибки возвращаются безопасно, а внутренние подробности доступны только ответственным за сопровождение. Учебный endpoint не обязан демонстрировать все production-настройки в одном гигантском фрагменте, но их ответственность должна быть понятна.

Практика различия 401 и 403

В задании x-user специально представляет уже проверенный контекст учебного теста. Это имитация authentication-стадии, а не рекомендованный способ входа в реальном приложении. Без пользователя возвращается 401, с чужим владельцем — 403, с подходящим — 200. Такая модель выделяет именно правило доступа и порядок проверок.

Проверьте отсутствие пользователя, владельца и другого пользователя. После решения замените учебную подстановку реальным адаптером сессии в итоговом проекте, не меняя саму политику владения. Затем добавьте отрицательный тест попытки изменить чужую запись. Он должен проверять не только статус, но и отсутствие нежелательного изменения данных.

Загружаем редактор…

Музыка: Reverie — Scott Buckley · CC BY 4.0