Файлы cookie HttpOnly, PWA, экспресс, экспресс-сеанс, паспорт и выход из системы

В отличие от обычных файлов cookie, файлы cookie HttpOnly предназначены для предотвращения доступа к Javascript. Это делает их полезными для смягчения последствий XSS-атак.

Включение их для файлов cookie сеанса на моем сайте - легкая победа. Если вы похожи на меня, вы не думали дважды, пока не пришло время реализовать функцию выхода из системы. Без возможности сделать недействительным файл cookie сеанса через Javascript, пользователь должен быть в сети, чтобы выйти из системы. Учитывая, что автономное использование является одним из ключевых клиентов PWA, это крайне неудобно:

Одна из рекомендаций по решению этой проблемы:

  1. Используйте два файла cookie: один файл cookie HttpOnly, а другой - нет.
  2. Требовать оба куки для аутентификации.
  3. Если пользователь хочет выйти из системы в автономном режиме, удалите файл cookie, не относящийся к HttpOnly, и очистите внутреннее состояние вашего приложения.

Это решение дает вам преимущества безопасности файлов cookie HttpOnly без затруднений, связанных с возможностью выхода только онлайн-пользователей.

Здорово! Но не сразу понятно, как это можно реализовать, учитывая множество модулей npm, которые я использую для запуска своего приложения и выполнения моей аутентификации. Предполагая, что у вас уже есть сервер, настроенный как этот (экспресс, экспресс-сессия, паспорт), вот мое решение:

Сначала создайте этот файл cookie, не относящийся к HttpOnly, при первой аутентификации пользователя. Этот файл cookie будет содержать токен; этот токен также сохраняется в сеансе. Хотя в последних версиях экспресс-сеанса это не требуется, промежуточный модуль cookie-parser необходим для создания этого дополнительного файла cookie.

Во-вторых, добавьте промежуточное ПО, которое извлекает этот токен из сеанса и сравнивает его с токеном в файле cookie. Если он не совпадает, выйдите из системы. Эту аутентификацию необходимо вызывать откуда-то, где у нас есть доступ к сеансу, поэтому после app.use(passport.session()), но перед любым из ваших маршрутов, требующих авторизации.

Для развернутых приложений эта реализация имеет дополнительное преимущество, позволяя вам сохранять существующие сеансы. Если в сеансе не хранится токен, отличный от HttpOnly, не применяйте второй файл cookie. Вместо этого сгенерируйте файл cookie, отличный от HttpOnly, для аутентифицированного пользователя, чтобы мы могли «обновить» этого пользователя до нашей новой и улучшенной модели с двумя файлами cookie.

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

document.cookie = 'secondaryAuthToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';

И presto: