Laravel 5.6 - Passport JWT httponly cookie-аутентификация SPA для самопотребляющего API?

ПРИМЕЧАНИЕ: у меня было 4 щедрости на этот вопрос, но ни один из приведенных ниже ответов не является ответом, необходимым для этого вопроса. Все, что нужно, находится в обновлении 3 ниже, просто для поиска кода Laravel для реализации.


ОБНОВЛЕНИЕ 3: Эта блок-схема - именно тот поток, который я пытаюсь выполнить, все ниже - оригинальный вопрос с некоторыми более старыми обновлениями. Эта блок-схема суммирует все необходимое.

Зеленые части в блок-схеме ниже - это те части, которые я знаю как делать. Красные части вместе с примечаниями к ним - вот то, что я ищу для помощи в использовании кода Laravel.

enter image description here


Я провел много исследований, но информация всегда была короткой и неполной, когда дело доходит до использования Laravel с cookie файлом JWT httponly для самопотребляющего API (большинство онлайн-уроков показывают только то, что JWT хранится в локальном хранилище, которое не очень безопасно).). Похоже, что файл cookie httponly, содержащий JWT by Passport, должен использоваться для идентификации пользователя на стороне Javascript при отправке с каждым запросом к серверу для проверки того, что пользователь является тем, кем они себя называют.

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

  1. Laravel Passport (не tymon auth) для генерации зашифрованного JWT и отправки его в виде файла cookie httponly в качестве ответа после входа в систему со стороны JS. Какое промежуточное программное обеспечение использовать? Если токены обновления повышают безопасность, как это сделать?
  2. JavaScript (например, axios) api-псевдокод API, который выполняет вызов к конечной точке аутентификации, как cookie файл httponly передается в бэкэнд и как бэкенд проверяет токен.
  3. Если в одну учетную запись вошли с нескольких устройств, то устройство украдено, как отозвать доступ со всех устройств с аутентифицированным пользователем (если пользователь меняет пароль с зарегистрированного устройства, которым он управляет)?
  4. Как бы выглядели методы контроллера "Вход/Регистрация", "Выход из системы", "Смена пароля", "Забыли пароль" для создания/проверки/отзыва токенов?
  5. Интеграция токенов CSRF.

Я надеюсь, что ответ на этот вопрос послужит простым руководством для будущих читателей и тех, кто в данный момент пытается найти ответ, охватывающий вышеперечисленные вопросы о самопотребляющем API.

ОБНОВЛЕНИЕ 1:

  1. Обратите внимание, что я пробовал CreateFreshApiToken раньше, но это не сработало, когда дело доходит до отзыва токенов пользователя (для пунктов 3 и 4 выше). Это основано на этом комментарии основного разработчика Laravel, когда речь идет о промежуточном программном обеспечении CreateFreshApiToken:

Токены JWT, созданные этим промежуточным ПО, нигде не хранятся. Они не могут быть отозваны или "не существуют". Они просто предоставляют способ авторизации ваших вызовов API через cookie файл laravel_token. Это не связано с токенами доступа. Кроме того: вы обычно не используете токены, выпущенные клиентами в том же приложении, которое их выпускает. Вы бы использовали их в первом или стороннем приложении. Либо используйте промежуточное программное обеспечение, либо клиент выпустил токены, но не оба одновременно.

Таким образом, кажется, что он может обслуживать пункты 3 и 4 для отзыва токенов, это невозможно сделать при использовании промежуточного программного обеспечения CreateFreshApiToken.

  1. На стороне клиента кажется, что Authorization: Bearer <token> - это не тот путь, когда имеешь дело с безопасным файлом cookie httpOnly. Я думаю, что запрос/ответ должен включать в себя защищенный файл cookie httpOnly в качестве заголовка запроса/ответа, например, на основе документов laravel:

При использовании этого метода аутентификации скаффолдинг Laravel JavaScript по умолчанию указывает Axios всегда отправлять заголовки X-CSRF-TOKEN и X-Requested-With.

headerswindow.axios.defaults.headers.common = {
    'X-Requested-With': 'XMLHttpRequest',
    'X-CSRF-TOKEN': (csrf_token goes here)
};

Это также причина, по которой я ищу решение, которое охватывает все пункты выше. Извиняюсь, я использую Laravel 5.6, а не 5.5.

ОБНОВЛЕНИЕ 2:

Похоже, что комбинация Password Grant/Refresh Token Grant - это то, что нужно. Ищите простое в использовании руководство по внедрению с использованием паролей Grant/Refresh Token Grant.

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

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

Я ищу простой в реализации, понятный и целостный ответ, используя комбо " Предоставление пароля/Обновление токена", которое охватывает все части вышеупомянутых оригинальных 5 пунктов с помощью httpOnly secure cookie, создания/отзыва/обновления токенов, создания cookie входа в систему, отмена cookie для выхода из системы, методы контроллера, CSRF и т.д.

Ответы

Ответ 1

Laravel Passport JWT

  1. Чтобы использовать эту функцию, вам необходимо отключить сериализацию файлов cookie. В Laravel 5.5 есть проблема с сериализацией/десериализацией значений cookie. Вы можете прочитать больше об этом здесь (https://laravel.com/docs/5.5/upgrade)

  2. Удостоверься что

    • у вас есть <meta name="csrf-token" content="{{ csrf_token() }}"> в <meta name="csrf-token" content="{{ csrf_token() }}"> шаблона вашего <meta name="csrf-token" content="{{ csrf_token() }}">

    • axios настроен на использование csrf_token для каждого запроса.

У вас должно быть что-то подобное в resources/assets/js/bootstrap.js

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
  window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
  console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
  1. Настройка маршрутов аутентификации описана здесь (https://laravel.com/docs/5.5/authentication)
  2. Настройка паспорта объяснена здесь (https://laravel.com/docs/5.5/passport).

Важными частями являются:

  • добавьте черту Laravel\Passport\HasApiTokens в вашу модель User
  • установите опцию driver защиты аутентификации api для passport в вашем config/auth.php
  • добавьте \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class, middleware к вашей группе web промежуточного программного обеспечения в app/Http/Kernel.php

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

  1. Сделайте POST-запрос к /login передав ваши учетные данные. Вы можете сделать запрос AJAX или отправить обычную форму.

Если запросом на вход является AJAX (с использованием axios), ответными данными будет HTML, но вас интересует код состояния.

axios.get(
  '/login, 
  {
    email: '[email protected]',
    password: 'secret',
  },
  {
    headers: {
      'Accept': 'application/json', // set this header to get json validation errors.
    },
  },
).then(response => {
  if (response.status === 200) {
      // the cookie was set in browser
      // the response.data will be HTML string but I don't think you are interested in that
    }
    // do something in this case
}).catch(error => {
  if (error.response.status === 422) {
    // error.response.data is an object containing validation errors
  }
  // do something in this case
});

При входе в систему сервер находит пользователя по предоставленным учетным данным, генерирует токен на основе информации о пользователе (id, email...) (этот токен нигде не сохраняется), затем сервер возвращает ответ с зашифрованным файлом cookie, который содержит сгенерированный токен,

  1. Сделайте вызов API для защищенного маршрута.

Предполагая, что у вас есть защищенный маршрут

Route::get('protected', '[email protected]')->middleware('auth:api');

Вы можете сделать AJAX-вызов, используя Axios, как обычно. Файлы cookie устанавливаются автоматически.

axios.get('/api/protected')
  .then(response => {
    // do something with the response
  }).catch(error => {
    // do something with this case of error
  });

Когда сервер получает вызов, он расшифровывает запрос laravel_cookie и получает информацию о пользователе (например, id, email...). Затем с этой информацией о пользователе выполняется поиск в базе данных, чтобы проверить, существует ли пользователь. Если пользователь найден, он получает доступ к запрошенному ресурсу. Остальное 401 возвращается.

Аннулирование токена JWT. Поскольку вы упоминаете комментарий, вам не нужно беспокоиться об этом, так как этот токен нигде не сохраняется на сервере.

Обновить

Что касается пункта 3, в Laravel 5.6 Auth появился новый метод logoutOtherDevices. Вы можете узнать больше здесь (https://laracasts.com/series/whats-new-in-laravel-5-6/episodes/7), поскольку документация очень легкая.

Если вы не можете обновить свою версию Laravel, вы можете проверить, как это делается в 5.6 и построить свою собственную реализацию для 5.5

Пункт 4 из вашего вопроса. Взгляните на контроллеры, найденные в app/Http/Controllers/Auth.

Что касается access_tokens и refresh_tokens, это совершенно другой и более сложный подход. Вы можете найти много онлайн-уроков, объясняющих, как это сделать.

Я надеюсь, что это помогает.

PS. Счастливого Нового года!! :)

Ответ 2

  • Laravel Passport - это реализация OAuth-сервера The PHP League
  • Тип предоставления пароля может использоваться для аутентификации по имени пользователя и паролю
  • Не забудьте скрыть свои учетные данные клиента, сделав запрос авторизации в прокси
  • Сохраните токен обновления в файле cookie HttpOnly, чтобы минимизировать риск XSS-атак.

Больше информации вы можете увидеть здесь

http://esbenp.github.io/2017/03/19/modern-rest-api-laravel-part-4/

Ответ 3

Я также применил паспорт Laravel в своем проекте и думаю, что рассмотрел большинство вопросов, которые вы упомянули в своем вопросе.

  1. Я использовал предоставление пароля для создания токена доступа и обновления токена. Вы можете выполнить следующие действия, чтобы настроить паспорт и реализовать его. В вашем методе входа в систему вы должны проверить учетные данные пользователя и сгенерировать токены и прикрепить cookie (прикрепление cookie к ответу) к ответу. Если вам нужно, я могу привести несколько примеров.
  2. Я добавил два промежуточного программного обеспечения для CORS (обработка заголовков входящих запросов) и для проверки, является ли входящий токен доступа действительным или нет, если он недействителен, генерирует токен доступа из сохраненного токена обновления (токен обновления). Я могу показать вам пример.
  3. После входа в систему весь запрос со стороны клиента должен содержать заголовок Authorization: Bearer <token> (Authorization: Bearer <token>).

Дайте мне знать, если вы согласны с вышеуказанными пунктами.

Ответ 4

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

Какой тип гранта OAuth 2.0 мне следует использовать?

Это первое, что нужно решить. Когда дело доходит до SPA, возможны два варианта:

  1. Предоставление кода авторизации (рекомендуется при условии, что секрет клиента хранится на стороне сервера)
  2. Предоставление учетных данных паролем владельца ресурса

Причины, по которым я не упоминаю тип неявного предоставления в качестве опции:

  1. Шаг аутентификации клиента путем предоставления секрета клиента и кода авторизации отсутствует. Так меньше безопасности
  2. Токен доступа отправляется обратно в виде фрагмента URL (чтобы токен не отправлялся на сервер), который будет оставаться в истории браузера.
  3. Если происходит XSS-атака, вредоносный скрипт может очень хорошо отправить токен на удаленный сервер, контролирующий злоумышленника.

(Тип гранта Client Credentials не входит в сферу данного обсуждения, поскольку он используется, когда клиент не действует от имени пользователя. Например, для пакетного задания)

В случае типа предоставления кода авторизации сервер авторизации обычно отличается от сервера ресурсов. Лучше хранить сервер авторизации отдельно и использовать его как общий сервер авторизации для всех SPA в организации. Это всегда рекомендуемое решение.

Здесь (в типе предоставления кода авторизации) поток выглядит следующим образом:

  1. пользователь нажимает кнопку входа на целевой странице SPA
  2. пользователь перенаправляется на страницу входа на сервер авторизации. Идентификатор клиента указывается в параметре запроса URL
  3. Пользователь вводит свои учетные данные и нажимает кнопку входа. Имя пользователя и пароль будут отправлены на сервер авторизации с использованием HTTP POST. Учетные данные следует отправлять в теле или заголовке запроса, а НЕ в URL (так как URL-адреса регистрируются в истории браузера и на сервере приложений). Кроме того, должны быть установлены надлежащие заголовки кэширования HTTP, чтобы учетные данные не кэшировались: Cache-Control: no-cache, no-store, Pragma: no-cache, Expires: 0
  4. Сервер авторизации аутентифицирует пользователя на основе пользовательской базы данных (скажем, сервера LDAP), где имя пользователя и хэш пароля пользователя (алгоритмы хеширования, такие как Argon2, PBKDF2, Bcrypt или Scrypt) хранятся со случайной солью.
  5. При успешной аутентификации сервер авторизации получит из своей базы данных URL-адрес перенаправления по указанному идентификатору клиента в параметре запроса URL-адреса. URL перенаправления - это URL сервера ресурсов.
  6. Затем пользователь будет перенаправлен на конечную точку сервера ресурсов с кодом авторизации в параметре запроса URL.
  7. Затем сервер ресурсов отправит HTTP-запрос POST серверу авторизации для получения токена доступа. Код авторизации, идентификатор клиента, секрет клиента должны быть указаны в теле запроса. (Следует использовать соответствующие заголовки кэширования, как указано выше)
  8. Сервер авторизации возвращает токен доступа и токен обновления в теле или заголовке ответа (с соответствующим заголовком кэширования, как упомянуто выше)
  9. Сервер ресурсов теперь перенаправляет пользователя (код ответа HTTP 302) на URL-адрес SPA, устанавливая соответствующие файлы cookie (что будет подробно объяснено ниже)

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

Также смотрите мой ответ на это здесь для получения более подробной информации о владелец ресурса типа гранта.

Здесь может быть важно отметить, что в SPA все защищенные маршруты должны быть включены только после вызова соответствующей службы, чтобы убедиться, что в запросе присутствуют действительные токены. Точно так же защищенные API должны также иметь соответствующие фильтры для проверки токенов доступа.

Почему я не должен хранить токены в браузере localalstorage или sessionstorage?

Многие SPA хранят токен доступа и/или обновляют в локальном хранилище браузера или сеансе хранения. Я думаю, что мы не должны хранить токены в этих хранилищах браузера:

  1. Если происходит XSS, вредоносный скрипт может легко прочитать токены оттуда и отправить их на удаленный сервер. На удаленном сервере или злоумышленнике не возникнет проблем с выдачей себя за пользователя-жертву.

  2. localstorage и sessionstorage не являются общими для поддоменов. Таким образом, если у нас есть два SPA, работающих на разных поддоменах, мы не получим функцию единого входа, потому что токен, сохраненный одним приложением, не будет доступен для другого приложения в организации.

Однако, если токены все еще хранятся в любом из этих хранилищ браузера, необходимо включить надлежащий fingerprint. Отпечаток пальца - это криптографически сильная случайная строка байтов. Строка Base64 необработанной строки будет затем сохранена в SameSite cookie HttpOnly, Secure, SameSite с префиксом имени __Secure-. Правильные значения для атрибутов Domain и Path. Хэш строки SHA256 также будет передан в заявке JWT. Таким образом, даже если атака XSS отправляет токен доступа JWT удаленному серверу, управляемому злоумышленником, он не может отправить исходную строку в файле cookie, и в результате сервер может отклонить запрос на основании отсутствия файла cookie. Кроме того, XSS и внедрение сценариев могут быть дополнительно смягчены с помощью соответствующего заголовка ответа content-security-policy.

Замечания:

  1. SameSite=strict гарантирует, что данный файл cookie не будет сопровождать запросы, SameSite=strict с другого сайта (AJAX или по следующей гиперссылке). Проще говоря - любой запрос, исходящий от сайта с тем же "регистрируемым доменом", что и целевой сайт, будет разрешен. Например, если " http://www.example.com " является именем сайта, регистрируемый домен - "example.com". Для получения дополнительной информации обратитесь к Ссылка №. 3 в последнем разделе ниже. Таким образом, он обеспечивает некоторую защиту от CSRF. Однако это также означает, что если указан URL-адрес форума, прошедший проверку пользователь не может перейти по ссылке. Если это серьезное ограничение для приложения, SameSite=lax можно использовать SameSite=lax, который разрешит межсайтовые запросы, если методы HTTP безопасны. ПОЛУЧИТЕ, ГОЛОВУ, ВАРИАНТЫ И TRACE. Поскольку CSRF основан на небезопасных методах, таких как POST, PUT, DELETE, lax прежнему обеспечивает защиту от CSRF.

  2. Чтобы разрешить передачу cookie во всех запросах на любой поддомен "example.com", атрибут домена cookie должен быть установлен как "example.com"

Почему я должен хранить токен доступа и/или обновлять токен в куки?

  1. При хранении токенов в cookie- httpOnly мы можем установить cookie как secure и httpOnly. Таким образом, если XSS происходит, вредоносный скрипт не может прочитать и отправить их на удаленный сервер. XSS может по-прежнему выдавать себя за пользователя из браузера пользователя, но если браузер закрыт, скрипт не сможет нанести дальнейший ущерб. secure флаг гарантирует, что токены не могут быть отправлены через незащищенные соединения - SSL/TLS является обязательным
  2. Например, установка корневого домена в файле cookie как domain=example.com гарантирует, что файл cookie будет доступен во всех поддоменах. Таким образом, разные приложения и серверы в организации могут использовать одни и те же токены. Логин требуется только один раз

Как мне проверить токен?

Токены обычно являются токенами JWT. Обычно содержимое токена не является секретным. Следовательно они обычно не зашифрованы. Если требуется шифрование (возможно, из-за того, что некоторая конфиденциальная информация также передается внутри токена), существует отдельная спецификация JWE. Даже если шифрование не требуется, нам необходимо обеспечить целостность токенов. Никто (пользователь или злоумышленник) не должен иметь возможности изменять токены. Если они это сделают, сервер должен быть в состоянии обнаружить это и отклонить все запросы с поддельными токенами. Чтобы обеспечить эту целостность, токены JWT имеют цифровую подпись с использованием такого алгоритма, как HmacSHA256. Для генерации этой подписи необходим секретный ключ. Сервер авторизации будет владеть и защищать секрет. Всякий раз, когда api сервера авторизации вызывается для проверки токена, сервер авторизации пересчитывает HMAC на переданном токене. Если он не совпадает с входным HMAC, он возвращает отрицательный ответ. Токен JWT возвращается или сохраняется в кодированном формате Base64.

Однако для каждого вызова API на сервере ресурсов сервер авторизации не участвует в проверке токена. Сервер ресурсов может кэшировать токены, выданные сервером авторизации. Сервер ресурсов может использовать сетку данных в памяти (то есть Redis) или, если все не может быть сохранено в ОЗУ, базу данных на базе LSM (то есть Riak с уровнем DB) для хранения токенов.

Для каждого вызова API сервер ресурсов проверяет свой кэш.

  1. Если токен доступа отсутствует в кэше, API должны возвращать соответствующее ответное сообщение и код ответа 401, чтобы SPA мог перенаправить пользователя на соответствующую страницу, где пользователю будет предложено повторно войти в систему.

  2. Если токен доступа действителен, но срок его действия истек (обратите внимание, что токены JWT обычно содержат имя пользователя и дату окончания срока действия, помимо прочего), API должны возвращать соответствующее ответное сообщение и код ответа 401, чтобы SPA мог вызывать соответствующий API сервера ресурсов для обновить токен доступа с помощью маркера обновления (с соответствующими заголовками кэша). Затем сервер вызывает сервер авторизации с токеном доступа, токеном обновления и секретом клиента, а сервер авторизации может возвращать новые токены доступа и обновления, которые в конечном итоге передаются в SPA (с соответствующими заголовками кэша). Затем клиент должен повторить исходный запрос. Все это будет обрабатываться системой без вмешательства пользователя. Можно создать отдельный файл cookie для хранения токена обновления, аналогичного токену доступа, но с соответствующим значением атрибута Path, чтобы токен обновления не сопровождал каждый запрос, но был доступен только в запросах на обновление

  3. Если токен обновления недействителен или срок его действия истек, API должны возвращать соответствующее ответное сообщение и код ответа 401, чтобы SPA мог перенаправить пользователя на соответствующую страницу, где пользователю будет предложено повторно войти в систему.

Зачем нам два токена - токен доступа и токен обновления?

  1. Маркер доступа обычно имеет короткий срок действия, скажем, 30 минут. Обновление токена обычно длится более 6 месяцев. Если токен доступа каким-либо образом скомпрометирован, злоумышленник может выдать себя за пользователя-жертву только до тех пор, пока токен доступа действителен. Поскольку у злоумышленника не будет секрета клиента, он не сможет запросить у сервера авторизации новый токен доступа. Однако злоумышленник может запросить сервер ресурсов на обновление токена (как в приведенной выше настройке, запрос на обновление проходит через сервер ресурсов, чтобы избежать сохранения секретного ключа клиента в браузере), но с учетом других принятых шагов это маловероятно и, более того, сервер может принять дополнительные меры защиты на основе IP-адреса.

  2. Если этот короткий срок действия токена доступа помогает серверу авторизации отозвать выданные токены от клиентов, если это необходимо. Сервер авторизации также может поддерживать кеш выданных токенов. Администраторы системы могут при необходимости пометить токены определенных пользователей как отозванные. По истечении срока действия маркера доступа, когда сервер ресурсов перейдет на сервер авторизации, пользователь будет вынужден снова войти в систему.

А как насчет CSRF?

  1. Чтобы защитить пользователя от CSRF, мы можем следовать подходу, используемому в таких средах, как Angular (как описано в документации Angular HttpClient, где сервер должен отправлять не-HttpOnly cookie (другими словами, читаемый cookie), содержащий уникальный непредсказуемый значение для этого конкретного сеанса. Это должно быть криптографически сильное случайное значение. Затем клиент всегда будет читать файл cookie и отправлять значение в настраиваемом заголовке HTTP (кроме запросов GET & HEAD, которые не должны иметь какой-либо логики изменения состояния. Примечание CSRF не может читать что-либо из целевого веб-приложения из-за одной и той же политики происхождения), чтобы сервер мог проверить значение из заголовка и файла cookie. Поскольку междоменные формы не могут прочитать файл cookie или установить собственный заголовок, в случае запросов CSRF пользовательское значение заголовка будет отсутствовать, и сервер сможет обнаружить атаку

  2. Чтобы защитить приложение от входа в CSRF, всегда проверяйте заголовок referer и принимайте запросы только тогда, когда referer является доверенным доменом. Если заголовок referer отсутствует или домен не занесен в белый список, просто отклоните запрос. При использовании SSL/TLS referrer обычно присутствует. Целевые страницы (которые в основном являются информационными и не содержат форму входа или какой-либо защищенный контент) могут быть немного смягчены и разрешать запросы с отсутствующим заголовком referer

  3. HTTP-метод TRACE должен быть заблокирован на сервере, так как его можно использовать для чтения httpOnly cookie httpOnly

  4. Также установите заголовок Strict-Transport-Security: max-age=<expire-time>; includeSubDomains Strict-Transport-Security: max-age=<expire-time>; includeSubDomains чтобы разрешить только защищенные соединения, чтобы предотвратить перезапись cookie файлов CSRF из поддоменов любым посредником.

  5. Кроме того, необходимо SameSite настройку SameSite как указано выше.

Наконец, SSL/TLS является обязательным для всех видов связи - так как на сегодняшний день версии TLS ниже 1.1 неприемлемы для соответствия PCI/DSS. Для обеспечения прямой секретности и аутентифицированного шифрования должны использоваться надлежащие комплекты шифров. Кроме того, токены доступа и обновления должны быть помещены в черный список, как только пользователь явно нажмет "Выход", чтобы предотвратить любую возможность неправильного использования токенов.

Рекомендации

  1. RFC 6749 - OAuth2.0
  2. Шпаргалка OWASP JWT
  3. SameSite Cookie IETF Draft
  4. Префиксы печенья
  5. RFC 6265 - Cookie

Ответ 5

В моем проекте реализован Laravel Passport, и все работает хорошо, кроме времени истечения срока хранения файлов cookie, в котором хранятся токены (это всего 1 час).

Мой проект состоит из бэкэнда Laravel 5.8 api (с паспортом Laravel), который обслуживает фронтальное приложение SPA (Vue).

Пользователи из моего приложения могут успешно войти в систему, используя страницу с компонентом Vue, который отправляет запрос POST с учетными данными пользователя, и, если вход успешно выполнен, пользователи перенаправляются на новый URL-адрес (домашнее приложение) - это перенаправление является запросом GET который создает cookie "laravel_token", созданный промежуточным программным обеспечением CreateFreshApiToken.

Отныне пользователи могут перемещаться в любом месте внутри приложения, и все данные, необходимые из компонентов приложения, получаются с помощью вызовов ajax (Laravel заметит наличие файла cookie "laravel_token" в этих вызовах ajax и идентифицирует вошедшего в систему пользователя, используя JWT присутствует в этом cookie).

Моя проблема:

Файл cookie "laravel_token", который был создан при входе пользователя, был создан со сроком действия всего 1 час. Поскольку это SPA, этот файл cookie никогда не обновляется (обменивается на новый с новым временем жизни)... поэтому через 1 час, когда необходимо выполнить новый ajax-запрос к внутреннему серверу Laravel, он будет получить неаутентифицированный ответ - это имеет смысл, потому что файл cookie laravel_token устарел.

Как вы справляетесь с этой проблемой?

Я знаю, что могу обновить этот файл cookie, выполнив полное обновление/перезагрузку страницы до истечения срока действия этого файла cookie, но это не очень хорошее решение с точки зрения взаимодействия с пользователем.

Я не могу сделать ajax-вызов, чтобы обновить этот cookie, потому что это SPA, и у меня нет client_id и его секрета со стороны клиента... а также потому, что не только этот cookie является httponly, но и зашифрован Laravel - так что я не могу обменять его на новый, используя JS.

Является ли единственное решение, увеличивающее срок службы этого файла cookie (например, с 1 часа до.... 1 года)? Вы видите какие-либо проблемы с этим? И где я могу установить этот срок действия куки? Нужно ли расширять класс ApiTokenCookieFactory?

Я хотел бы, чтобы пользователь входил в систему до тех пор, пока он намеренно не выполнит запрос на выход из системы или не истечет срок действия access_token (который, в моем случае, по умолчанию используется Laravel Passport, является долгоживущим токеном в 1 год).

Буду признателен, если кто-нибудь сможет мне помочь с этой проблемой.

Если вы видите что-то, что я делаю не правильно, я также буду признателен за ваши комментарии и предложения.

Большое спасибо!