Вопрос или проблема
В последние пару дней я читал всё, что мог, на эту тему, и не могу решить, какой будет лучший подход.
Единственными требованиями являются:
-
Мне нужно знать пользователей, которые вошли в систему, и все их сессии, чтобы пользователь мог видеть список с этой информацией и иметь возможность закрыть любую сессию по своему выбору.
-
Обе приложения должны использовать одни и те же конечные точки REST API.
Сначала я использовал сессионные файлы cookie и вызывал API с параметром setCredentials=true, но я обнаружил, что мобильные приложения обрабатывают файлы cookie по-другому, и я не имею контроля над этим (например, они удаляются по ряду причин до истечения срока). Я подумал о том, чтобы сохранить файл cookie в локальном хранилище и добавлять его к каждому запросу, но я не могу получить доступ к файлу cookie ни в каком виде, потому что httpOnly установлен в true. Решением было бы установить httpOnly в false, но в этом случае я подставляю файл cookie и не уверен, какие меры безопасности мне следует принять, чтобы защитить его от кражи или подделки.
Другим решением было бы использовать JWT и хранить его в веб/локальном хранилище. Я также сохранил бы в таблице каждый все еще действующий токен (хэшированный с использованием алгоритма паролей), чтобы получить список вошедших пользователей и их сессий, и другую таблицу для недействительных токенов на случай, если пользователь решит завершить конкретную сессию / изменит пароль / и т. д. Но снова я не уверен в мерах безопасности, которые мне следует использовать с этим подходом. Должен ли я также зашифровать токен? Я думал о том, чтобы добавить к нему данные об устройстве, которое запрашивает токен, чтобы всегда проверять, что устройство, которое запрашивало токен, является тем, кто его использует. Что еще мне следует сделать, чтобы защитить этот токен?
Если я правильно реализую любой из этих вариантов, какой из них будет более безопасным как для веба, так и для мобильного?
Прежде чем перейти к деталям, я скажу, что как сессионные файлы cookie, так и JWT работают для вашего случая, и оба являются безопасными если реализованы правильно. Лично я бы выбрал JWT лишь потому, что с ним легче получить актуальную информацию или готовые решения.
JWT
JWT действительно предназначались для безгосударственной авторизации, но вы все равно можете использовать их для сессий. Вам стоит обратить внимание на использование модели токенов доступа/обновления, где вы отслеживаете активные токены обновления в вашей базе данных.
Что касается шифрования, то есть две основные реализации стандарта JWT, а именно JWS (подписанный токен) и JWE (подписанный, затем зашифрованный токен). Что вам следует иметь в виду, так это то, что подпись подписанного токена уже обеспечивает целостность токена. Вы бы реализовали JWE, только если передаете чувствительную информацию в токене, которую хотите скрыть от клиента. Тем не менее, сам по себе JWT не решает проблемы атак типа “человек посередине”, поэтому помните о необходимости использования SSL при передаче токена.
Хранение токена будет отличаться между вашим веб-приложением и мобильным нативным приложением. Для мобильных приложений вам следует хранить их в Keychain/Keystore ОС (скорее всего, через обертку), которая предназначена для этой цели. А вот где хранить JWT в браузере, с другой стороны, остается довольно спорной темой, так как хранение в webstorage (sessionStorage/localStorage) уязвимо для атак XSS, в то время как хранение внутри cookie уязвимо для CSRF.
Судя по всему, общая тенденция заключается в том, чтобы избегать webstorage из-за его большей площади атаки, но, честно говоря, я видел примеры обоих методов. Для одностраничных приложений вы также можете рассмотреть возможность хранения токена в памяти без постоянного хранилища.
Сессионные файлы cookies
Не зная деталей вашего мобильного приложения, трудно сказать, но из моего опыта, если вы используете механизмы CookieManager/NSHTTPCookieStorage, предоставляемые Google/iOS, не должно быть проблемы с удалением файлов cookie, о которых вы упомянули.
Хранение файлов cookie в браузере потребует от вас защиты от CSRF. То, какую защиту вам следует использовать, будет сильно зависеть от вашей конкретной серверной реализации и ограничений. Я думаю, вам следует ознакомиться с материалами на OWASP или задать более конкретный вопрос.
Я возобновляю старую тему, чтобы предложить, что для веб-приложений вы должны хранить JWT в cookie, чтобы избежать неприятностей при его передаче вручную.
Для локального хранения на устройстве убедитесь, что как мобильное, так и веб-приложения извлекают JWT из API, чтобы сохранить метод шифрования скрытым на мобильной стороне.
В веб-приложении вы можете управлять этим на стороне сервера для повышения безопасности.
Вы доверяете всему вашему клиентскому коду? Если да, вы можете хранить идентификаторы сессий в локальном хранилище и убедиться, что отправляете их с каждым HTTP-запросом. На вашей стороне сервера просто имейте таблицу с хэшом идентификатора сессии в качестве первичного ключа и идентификатором пользователя в качестве внешнего ключа, а также временем истечения. Не храните список удаленных сессий, просто удалите строку (или отметьте ее как удаленную).
Риск с файлами cookie заключается в том, что они отправляются с каждым HTTP-запросом на ваш домен, даже если он происходит от поддельного клиента. Это называется CSRF. Если у вас нет какой-либо защиты от CSRF, избегайте файлов cookie и используйте локальное хранилище.
Конечно, если вы не можете доверять всему вашему клиентскому коду, вам потребуется другое решение.
Также, если вы используете HTTPS, идентификаторы сессий, как файлы cookie, так и отправки форм, будут зашифрованы.
Ответ или решение
JWT против сессионных куки для API для веб- и мобильных приложений
Выбор между использованием JWT (JSON Web Token) и сессионными куки для авторизации в API может быть сложной задачей, особенно с учетом ваших требований и особенностей работы веб- и мобильных приложений. Давайте рассмотрим оба подхода подробнее, принимая во внимание ваши специфические нужды.
Основные требования
- Отслеживание пользователей и сессий: Необходимо иметь возможность видеть всех пользователей, которые вошли в систему, и все их активные сессии, с возможностью завершения любой из них.
- Использование одних и тех же конечных точек API: Оба приложения должны иметь доступ к одним и тем же API.
Sессионные куки
Сессионные куки традиционно используются для управления авторизацией и работают следующим образом:
-
Безопасность: Если правильно настроены, они могут быть довольно безопасными. Важно установить флаги
HttpOnly
иSecure
, чтобы защитить куки от XSS и MITM-атак. -
Управление сессиями: Сервер может легко отслеживать активные сессии через хранилище сессий, где каждая сессия хранится с привязкой к пользователю и может быть завершена по необходимости.
-
Проблемы с мобильными приложениями: Как вы уже заметили, мобильные приложения могут некорректно обрабатывать куки. Это может привести к потере сессии. Хранение куки в локальном хранилище (например, с помощью Secure Storage) может быть решением, но это связано с риском раскрытия куки.
JWT (JSON Web Token)
JWT представляет собой компактный и самостоятельный способ передачи информации между сторонами с использованием JSON. Он хорошо подходит для API и позволяет минимизировать нагрузку на сервер.
-
Статус авторизации: JWT не требуют хранения состояния на сервере, что делает их легковесным решением для авторизации. Однако вы можете хранить активные токены в базе данных и отмечать недействительные токены в случае выхода из системы.
-
Безопасность токенов: Подпись токена обеспечивает целостность данных. При необходимости, вы можете использовать JWE для шифрования токенов, если передаете конфиденциальную информацию.
-
Хранение токенов: В мобильных приложениях следует использовать системные хранилища (Keychain/Keystore), чтобы защитить токены. В веб-приложениях лучше использовать куки с настройками безопасности, такими как
SameSite
, для предотвращения CSRF-атак и защиты от XSS.
Рекомендации по безопасности
-
Использование HTTPS: Для защиты всех передаваемых данных в том числе токенов и куков обязательно используйте безопасное соединение HTTPS.
-
Управление доступом: Настройте систему так, чтобы токены имели срок действия и обновлялись с помощью Refresh-токенов. Это будет удобным способом управления авторизацией.
-
Управление сессиями: Для JWT реализуйте хранение токенов и их статусов в базе данных. Это поможет вам отслеживать активные сессии и предоставлять пользователям возможность завершать их.
-
Дополнительные меры предосторожности: Внедрите механизмы, которые обеспечивают защиту от атак на уровне API, включая проверку идентификаторов устройств и стабильности сессий.
Заключение
Выбор между JWT и сессионными куками зависит от ваших потребностей и архитектуры приложений. Если вы хотите простое и независимое решение для мобильных и веб-приложений, JWT может быть предпочтительнее. Однако, если вам требуется строгий контроль над сессиями и вы хотите использовать существующий подход с сессионными куками, убедитесь, что соблюдены все необходимые меры безопасности.
В конечном итоге наиболее важно правильно реализовать выбранный подход, следуя рекомендациям по безопасности и обеспечивая удобство для пользователей в управлении их сессиями.