Feathers: Добавить поддержку токенов обновления

Созданный на 22 дек. 2015  ·  64Комментарии  ·  Источник: feathersjs/feathers

В настоящее время мы разрешаем получить новый токен, разместив действительный токен аутентификации в <loginEndpoint>/refresh . У токенов обновления немного другой рабочий процесс, как описано здесь:
https://auth0.com/learn/refresh-tokens

Authentication Feature

Самый полезный комментарий

Эта функция ОБЯЗАТЕЛЬНА, когда дело касается приложений React Native. Пользователь входит в систему вначале, и когда он откроет приложение через несколько недель, он ожидает, что все еще будет в системе.

Все 64 Комментарий

: +1: Мы с @corymsmith говорили об этом. В надежде помочь кое-что из этого перебросить через финишную черту во время «праздников».

У нас есть поддержка этого в мастере, но также есть поддержка в ветке decoupling . Чтобы обновить токен, у вас есть 2 варианта:

  1. Вы можете повторно пройти аутентификацию, используя адрес электронной почты / пароль, Twitter и т. Д.
  2. Вы можете передать действительный токен GET /auth/token/refresh

У нас есть процесс обновления токенов, но не совсем полная поддержка токенов обновления, как описано в ссылке Auth0, которую я опубликовал выше. Фактический токен обновления работает аналогично коду / паролю аутентификации GitHub, но может использоваться только для получения нового токена JWT. Поэтому, даже если срок действия вашего токена JWT истекает, если у вас есть токен обновления, вы можете использовать его для повторного входа в систему. Они сохраняются в базе данных с неизменным идентификатором пользователя и могут быть отозваны в любое время. По крайней мере, это то, что я почерпнул из статьи Auth0.

Ах ты прав @marshallswain. Думаю, надо было нажать на ссылку: wink:

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

Я вроде как голосую за то, чтобы мы сделали это feathers-authentication 2.0.

Великие умы.

Я все еще в полном замешательстве, так как неясно, как именно работает рабочий процесс аутентификации.

То, что я сейчас делаю, есть.
1.) Клиент отправляет имя пользователя и пароль

 curl -X POST https://xxx/auth/local   -H "Content-Type: application/json"   -d '{ "email":"xxx", "password":"yyy"}'

Это возвращает токен JWT.

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NzhhNjUyN2RkMTZiMjIwMDRhY2ZjNmEiLCJpYXQiOjE0NzAzMjYyODUsImV4cCI6MTQ3MDQxMjY4NSwiaXNzIjoiZmVhdGhlcnMifQ.OVvQbnxfoDGxPFm3Y6tBhRae2Qa6_mDq-PVIo8RcC8Y"}

2.) Затем я помещаю этот токен в HTTP-заголовок Authorizatin для доступа к API.

curl -X GET https://xxx/users  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NzhhNjUyN2RkMTZiMjIwMDRhY2ZjNmEiLCJpYXQiOjE0NzAzMjU1NzYsImV4cCI6MTQ3MDQxMTk3NiwiaXNzIjoiZmVhdGhlcnMifQ._CHdx3RpEuI189t90mXq-IMPXRNuoVh7nBwY1ON7xCY'

Теперь я не понимаю, как на самом деле обновить этот токен.
Я пробовал отправить этот токен на xxx / auth / token / refresh
У меня просто еще один очень длинный жетон. Затем я попытался использовать как старый, так и этот новый токен для доступа к API. оба работают ... (не следует ли отключать старый?)

curl -X GET https://xxx/auth/token/refresh  -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NzhhNjUyN2RkMTZiMjIwMDRhY2ZjNmEiLCJpYXQiOjE0NzAzMjU1NzYsImV4cCI6MTQ3MDQxMTk3NiwiaXNzIjoiZmVhdGhlcnMifQ._CHdx3RpEuI189t90mXq-IMPXRNuoVh7nBwY1ON7xCY'
{"query":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NzhhNjUyN2RkMTZiMjIwMDRhY2ZjNmEiLCJpYXQiOjE0NzAzMjU1NzYsImV4cCI6MTQ3MDQxMTk3NiwiaXNzIjoiZmVhdGhlcnMifQ._CHdx3RpEuI189t90mXq-IMPXRNuoVh7nBwY1ON7xCY"},"provider":"rest","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJxdWVyeSI6eyJ0b2tlbiI6ImV5SjBlWEFpT2lKS1YxUWlMQ0poYkdjaU9pSklVekkxTmlKOS5leUpmYVdRaU9pSTFOemhoTmpVeU4yUmtNVFppTWpJd01EUmhZMlpqTm1FaUxDSnBZWFFpT2pFME56QXpNalUxTnpZc0ltVjRjQ0k2TVRRM01EUXhNVGszTml3aWFYTnpJam9pWm1WaGRHaGxjbk1pZlEuX0NIZHgzUnBFdUkxODl0OTBtWHEtSU1QWFJOdW9WaDduQndZMU9ON3hDWSJ9LCJwcm92aWRlciI6InJlc3QiLCJ0b2tlbiI6ImV5SjBlWEFpT2lKS1YxUWlMQ0poYkdjaU9pSklVekkxTmlKOS5leUpmYVdRaU9pSTFOemhoTmpVeU4yUmtNVFppTWpJd01EUmhZMlpqTm1FaUxDSnBZWFFpT2pFME56QXpNalUxTnpZc0ltVjRjQ0k2TVRRM01EUXhNVGszTml3aWFYTnpJam9pWm1WaGRHaGxjbk1pZlEuX0NIZHgzUnBFdUkxODl0OTBtWHEtSU1QWFJOdW9WaDduQndZMU9ON3hDWSIsImRhdGEiOnsiX2lkIjoiNTc4YTY1MjdkZDE2YjIyMDA0YWNmYzZhIiwiaWF0IjoxNDcwMzI1NTc2LCJleHAiOjE0NzA0MTE5NzYsImlzcyI6ImZlYXRoZXJzIiwidG9rZW4iOiJleUowZVhBaU9pSktWMVFpTENKaGJHY2lPaUpJVXpJMU5pSjkuZXlKZmFXUWlPaUkxTnpoaE5qVXlOMlJrTVRaaU1qSXdNRFJoWTJaak5tRWlMQ0pwWVhRaU9qRTBOekF6TWpVMU56WXNJbVY0Y0NJNk1UUTNNRFF4TVRrM05pd2lhWE56SWpvaVptVmhkR2hsY25NaWZRLl9DSGR4M1JwRXVJMTg5dDkwbVhxLUlNUFhSTnVvVmg3bkJ3WTFPTjd4Q1kifSwiaWF0IjoxNDcwMzI2NDQyLCJleHAiOjE0NzA0MTI4NDIsImlzcyI6ImZlYXRoZXJzIn0.TqUv3051TTGbX4cPfkN-6pOOB5SN9nH-E7TU1HHSsb8","data":{"_id":"578a6527dd16b22004acfc6a","iat":1470325576,"exp":1470411976,"iss":"feathers","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NzhhNjUyN2RkMTZiMjIwMDRhY2ZjNmEiLCJpYXQiOjE0NzAzMjU1NzYsImV4cCI6MTQ3MDQxMTk3NiwiaXNzIjoiZmVhdGhlcnMifQ._CHdx3RpEuI189t90mXq-IMPXRNuoVh7nBwY1ON7xCY"}}

Еще более странно то, что я попытался использовать этот новый токен и снова отправить его в / auth / token / refresh.
У меня жетон даже длиннее, чем этот.

Я не уверен, что я сделал неправильно или неправильно понял здесь. Пожалуйста, предложите.

@parnurzeal у нас пока нет поддержки токенов обновления. Вот почему это предлагаемая функция.

Чтобы получить новый токен, выполните POST для /auth/token с существующим действующим JWT или войдите в систему с использованием другого механизма аутентификации. Похоже, вы все делаете правильно.

Правильно, но, пожалуйста, посмотрите внимательно, как у меня получилось и на какой результат.

Возьмем простой пример.
Когда я запрашиваю новый токен, используя abcdefghijklmno (просто случайный бессмысленный токен).
Ответ - это просто более длинная версия предыдущего токена -> abcdefghijklmnopqrstuvwxyz
Если я попытаюсь сделать это снова, используя abcdefghijklmnopqrstuvwxyz , я получу его более длинную версию ->
abcdefghijklmnopqrstuvwxyz1234567890 и цикл продолжается (запрашивая больше, вы получаете более длинную более длинную версию предыдущего).

Кроме того, все три вышеуказанных токена можно использовать одновременно.
Разве срок действия предыдущего токена не истек после того, как мы запросим новый токен?

@parnurzeal, я говорю , не делайте того, что вы сделали, потому что эта функция на самом деле не реализована. На основе реализации (на данный момент) тот факт, что токен продолжает расти каждый раз, когда вы нажимаете /auth/token/refresh объясняется тем, что мы просто отправляем данные обратно в токен. Это не то, как он должен работать, и у нас не было времени закончить его, и почему это не задокументировано. Вы не должны его использовать.

Разве срок действия предыдущего токена не истек после того, как мы запросим новый токен?

Такова природа JWT. Срок их действия истекает сам по себе. Если вы хотите предотвратить использование старых токенов, срок действия которых еще не истек, вам необходимо вести черный список. В настоящее время это оставлено на ваше усмотрение, и у нас есть нерешенная проблема (# 133), но, скорее всего, мы не дойдем до этого в ближайшее время (если вообще когда-либо).

Привет, я заглянул в / auth / refresh / token и получил что-то вроде этого:

...
function pick (o, ...props) {
  return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]})));
}

// Provider specific config
const defaults = {
  payload: ['id', 'role'],
  passwordField: 'password',
  issuer: 'feathers',
  algorithm: 'HS256',
  expiresIn: '1d', // 1 day
};
...
// GET /auth/token/refresh
  get (id, params) {
    if (id !== 'refresh') {
      return Promise.reject(new errors.NotFound());
    }

    const options = this.options;

    // Add payload fields
    const data = pick(params.payload, options.payload);

    return new Promise(resolve => {
      jwt.sign(data, config.get('auth').token.secret, options, token => {
        return resolve({token: token});
      });
    });

  }

Это слишком наивно как реализация? В противном случае я мог бы попробовать отполировать, добавить пару тестов и создать пиар.

@aboutlo спасибо за усилия! Лучше подождать, пока не выйдет v0.8 (она уже некоторое время находится в альфа-версии), поскольку произошла куча изменений, и этот маршрут может исчезнуть на этой неделе.
Сегодня я делаю бета-версию и заканчиваю руководство по миграции. Так что это будет недолго, и v0.8 решает многие текущие проблемы с auth.

Мы много думали об обновлении токенов, поэтому после выпуска 0.8 (на этой неделе) я хотел бы обсудить этот вопрос. Скорее всего, я изложу наши предварительные мысли позже на этой неделе.

честно @ekryski , буду ждать 0.8 :)

Эта функция ОБЯЗАТЕЛЬНА, когда дело касается приложений React Native. Пользователь входит в систему вначале, и когда он откроет приложение через несколько недель, он ожидает, что все еще будет в системе.

@deiucanta: хорошая новость в том, что мы [email protected]. Я не думаю, что пройдет много времени, прежде чем мы его установим и задокументируем.

это хорошие новости! 👍 с нетерпением жду этого

@marshallswain Жду обновлений по этой функции. Пожалуйста, дайте мне знать, когда мы можем этого ожидать. Или он уже выпущен? Заранее спасибо.

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

@atulrpandey официально не выпущен, но реализовать его тоже несложно. Вы просто добавляете ловушку, чтобы сгенерировать новый токен обновления и сохранить его в пользовательском объекте в БД, и как только он будет использован или истечет срок его действия, вы удалите его у пользователя.

@petermikitsh еще одна вещь, которую вы можете сделать (если вы находитесь на мобильном телефоне), - это безопасно хранить clientId и clientSecret на клиенте, и если срок действия JWT accessToken истекает, вы просто повторно авторизуетесь с ними.

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

По теме токенов обновления:

Жетоны обновления несут информацию, необходимую для получения нового токена доступа. Другими словами, всякий раз, когда токен доступа требуется для доступа к определенному ресурсу, клиент может использовать токен обновления, чтобы получить новый токен доступа, выданный сервером аутентификации. Общие варианты использования включают получение новых токенов доступа после истечения срока действия старых или получение доступа к новому ресурсу в первый раз. Жетоны обновления также могут истекать, но они довольно долговечны. К токенам обновления обычно предъявляются строгие требования к хранению, чтобы гарантировать отсутствие утечки. Они также могут быть занесены в черный список сервером авторизации. - https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/

Так что я сам занялся React Native раньше, чем думал. Я думаю о том, чтобы внести свой вклад в это, но я хотел бы быть уверенным, что полностью понимаю механизм, чтобы убедиться, что это правильная реализация. Поскольку токены обновления не имеют состояния, будут некоторые ограничения на использование (например, разработчикам потребуется предоставить адаптер хранилища).

Можете ли вы использовать действующий JWT для получения токена обновления? Или токены обновления автоматически возвращаются в ответе аутентификации (например, в дополнение к accessToken )? Похоже, что Auth0 включает их в ответы на аутентификацию (как accessToken и refreshToken ) в своем примере на https://auth0.com/learn/refresh-tokens/.

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

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

Токены обновления на самом деле не обязательно должны истекать, но их можно вызвать, если они хранятся в базе данных, и таким образом пользователь также может видеть, сколько у них активных сеансов. Вы можете хранить больше информации при выдаче токенов обновления (например, os, ip, имя устройства и т. Д., Чтобы сделать их идентифицируемыми - например, как это делают Facebook, GitHub).

По крайней мере, я так делаю.

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

@marshallswain

В настоящее время мы разрешаем получить новый токен, разместив действительный токен аутентификации в <loginEndpoint>/refresh . У токенов обновления немного другой рабочий процесс ...

Поэтому его следует называть renew not refresh чтобы избежать путаницы <loginEndpoint>/renew

Как сказал @abhishekbhardwaj

accessToken не должен обновляться с помощью accessToken, а только с помощью refresehToken или имени пользователя / пароля, refreshToken должен обновляться только с помощью аутентификации пользователя / пароля или какого-либо другого секрета, который недоступен для браузера, например, 2-фактор автори ...

В настоящее время можно обновить свой accessToken с помощью accessToken, как упомянуто здесь:

https://github.com/feathersjs/authentication-jwt/issues/61

Другой подход - хранить токен обновления внутри полезной нагрузки accessToken, тогда текущий api обновления проверяет, не отозван ли токен обновления (через базу данных или вызов redis). Таким образом, токен обновления может быть простым идентификатором автоинкремента. Также обновите api, чтобы больше не проверять срок действия. Поскольку токен обновления (простое целое число) подписан токеном доступа, он безопасен.

Таким образом, изменения в текущей базе кода должны быть минимальными: для обновления API предоставьте способ, чтобы пользователь мог предоставить ловушку для проверки, не отозван ли токен доступа (путем проверки токена обновления внутри его полезной нагрузки), если этот хук предоставляется не t больше проверять срок действия.

Не могли бы вы объяснить этот подход еще @ arash16 ?

Если вы храните токен обновления в полезной нагрузке accessTokens, а API обновления не проверяет истечение срока действия, разве вы просто не сделали каждый accessToken «бессрочным»?

Потому что любой токен доступа можно использовать для получения нового токена доступа, верно?

Я что-то упускаю?

@BigAB
Я имел в виду не проверять истечение срока действия только для обновления api , один и тот же accessToken используется как в качестве токена обновления, так и в качестве токена доступа. Срок действия этого токена не истекает только для обновления и получения нового токена доступа, сам идентификатор обновления может быть отозван пользователем вручную .

Разработчик должен иметь db-table / redis для хранения всех идентификаторов обновления. Когда пользователю необходимо отозвать или выйти из некоторых (или всех) других сеансов, мы можем предоставить ему список всех идентификаторов обновления (плюс некоторая дополнительная информация, такая как браузер, дата создания и т. Д.), И он решит удалить (подписать -из) их выборочно. После этого, как только истечет срок действия фактического токена, содержащего эти идентификаторы обновления, API обновления отказывается выдавать новый.

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

Срок действия токена доступа может быть коротким (менее 10 минут), пользователь может закрыть страницу и уйти, позже, когда он откроет страницу, токен доступа уже истек, и он вышел из системы. Но идентификатор обновления внутри токена имеет гораздо более длительное время жизни, управляемое базой данных (например, 7 или 30 дней), а также может быть отменено вручную.

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

@ arash16 , мне нравится ваша идея хранить токен обновления внутри JWT доступа. Есть ли какой-нибудь пример, как получить этот токен обновления на стороне сервера?

Моя текущая проблема: если срок действия токена доступа истек, полезная нагрузка недоступна в контексте крючка перьев. Я думаю, путь будет использовать verifyJWT() полезности функции @feathersjs/authentication пакета, например , в самом начале app.service('authentication').hooks({ before: { create: ... } }) ?

Есть ли какой-нибудь осознанный способ использовать жетоны обновления в перьях прямо сейчас? Есть ли планы добавить для них поддержку?

Всем здравствуйте ,

Похоже, он все еще недоступен (или я что-то упустил). Не могли бы вы сообщить нам, когда он будет доступен? Я вижу, что есть хранилище токенов обновления паспорта. Кто-нибудь пробовал это?
https://github.com/fiznool/passport-oauth2-refresh

Привет @daffl ,
Может ли кто-нибудь помочь мне понять, как можно обновить токен для стратегии Google? Потому что у меня не будет пароля для сценария входа в Google?

Спасибо

Другой подход - хранить токен обновления внутри полезной нагрузки accessToken.

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

Токены обновления должны надежно храниться на клиенте, и никто, кроме этого клиента, не должен иметь к ним доступа!

@deiucanta: хорошая новость в том, что мы [email protected]. Я не думаю, что пройдет много времени, прежде чем мы его установим и задокументируем.

Это было опубликовано в 2016 году. Ребята, у вас все еще есть планы по поддержке этой обязательной функции?

Нет. Вы ничего не можете сделать с просроченным токеном. Кроме того, в пререлизе версии 4 гораздо проще использовать токены обновления. Запись в кулинарной книге о том, как это сделать, будет частью окончательной версии.

Кроме того, в пререлизе версии 4 гораздо проще использовать токены обновления.

Есть приблизительная дата выхода?

Запись в кулинарной книге о том, как это сделать, будет частью окончательной версии.

Не могли бы вы в двух словах объяснить, пока это руководство не будет выпущено, как это можно сделать на пререлизе v4?

@daffl пинг

Есть еще официальный способ сделать это? v4 здесь, и я ничего не вижу в документации

@daffl, не могли бы вы рассказать, как этого достичь с помощью 4.0 и без взлома службы аутентификации?

@MichaelErmer в качестве обходного пути вы можете использовать локальную или любую настраиваемую стратегию для обновления jwt, что не идеально, но отлично работает для внутренней связи, скажем, между worker и api.

function initAuth() {
  return async (ctx) => {
    if (ctx.path !== 'authentication') {
      const [authenticated, accessToken] = await Promise.all([
        ctx.app.get('authentication'),
        ctx.app.authentication.getAccessToken(),
      ]);

      if (!accessToken || !authenticated) {
        const result = await ctx.app.authenticate(apiLocalCreds);
        ctx.params = {
          ...ctx.params,
          ...result,
          headers: { ...(ctx.params.headers || {}), Authorization: result.accessToken },
        };
      } else {
        const { exp } = decode(accessToken);
        const expired = Date.now() / 1000 > exp - 60 * 60;
        if (expired) {
          const result = await ctx.app.authenticate(apiLocalCreds);
          ctx.params = {
            ...ctx.params,
            ...result,
            headers: { ...(ctx.params.headers || {}), Authorization: result.accessToken },
          };
        }
      }
    }
    return ctx;
  };
}

client
  .configure(rest(apiHost).superagent(superagent))
  .configure(auth(authConfig))
  .hooks({ before: [initAuth()] });

В настоящее время я использую этот хук after в v4 authentication , чтобы обновить свой accessToken через 20 дней ...

javascript
const {DateTime} = require ('luxon')
const RenewAfter = {days: 20}

module.exports = () => {
return async context => {
если (
context.method === 'создать' &&
context.type === 'после' &&
context.path === 'аутентификация' &&
context.data && context.data.strategy === 'jwt' &&
context.result &&
context.result.accessToken) {
// проверяем, нужно ли продлить токен
const payload = ожидание context.app.service ('аутентификация'). verifyAccessToken (context.result.accessToken)
const loadedAt = DateTime.fromMillis (payload.iat * 1000)
const RenewAfter = IssueAt.plus (RenewAfter)
const now = DateTime.local ()
if (сейчас> возобновить после) {
context.result.accessToken = ожидание context.app.service ('аутентификация'). createAccessToken ({sub: payload.sub})
}
}
возврат контекста
}
}
`` ''

Важно, чтобы этот хук был в after как последний хук, чтобы все проверки и т. Д. Прошли.

Есть ли планы интегрировать жетоны обновления в перья?

Я отвечаю на этот вопрос одним сообщением ранее.

Меня также интересует рабочий процесс обновления токенов. Является ли решение, составленное @ m0dch3n, хорошей практикой? Стоит ли реализовать это по-другому?

В моем случае весь рабочий процесс refreshToken лишь немного защищает от атак человека в середине, так что, если средний человек украдет accessToken, он, по крайней мере, не сможет его обновить и получить бесконечный доступ к ресурсам.

Он не защищает от XSS, потому что в этом случае злоумышленник может украсть все, что хранится на стороне клиента. Так же и refreshToken ...

Проблема в том, что если вы сделаете время истечения срока действия accessToken слишком маленьким (например, 5 минут), вам также придется обновлять его чаще. Человеку посередине нужно только в течение 5 минут прослушивать запросы клиентов, чтобы перехватить refreshToken, тогда ... Если вы увеличите срок действия, у него будет более длительный доступ с помощью только accessToken ...

Честно говоря, если какой-то клиент скажет мне, что его доступ украли, мне все равно нужно занести в черный список accessToken И refreshToken, чтобы быть уверенным. Так что я все равно вынужден делать запрос к БД по каждому запросу.

В моем случае, когда мне известно о таком случае, я занесу в черный список все токены доступа за последние 40 дней, потому что мои токены доступа имеют срок действия 40 дней ...

Использование HTTPS-запроса усложняет атаку посредника. Разве вы не используете HTTPS-запросы?

Конечно, я использую https, но есть 3 возможности украсть accessToken. Первый - на стороне клиента (например, XSS), второй - на транспорте (человек посередине), а третий - на стороне сервера.

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

Цель refreshToken состоит в том, чтобы сделать срок действия accessToken короче И не передавать более длинный или бесконечный действительный токен при КАЖДОМ запросе.

Таким образом, единственная безопасность, которую он обеспечивает, заключается в том, что из 100 запросов, то есть вы не делаете все 100 уязвимыми на транспорте, а только 1 запрос

Таким образом, в основном человек в средней атаке не может быть защищен с помощью refeshToken и, конечно же, не с помощью XSS ... Его можно уменьшить только за счет того, сколько раз вы передаете этот refreshToken ... Стоимость его передачи меньше однако, accessToken должен быть более действительным ...

Я просто копирую / вставляю свои комментарии из канала Slack:

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

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

Токен обновления можно отозвать в случае взлома учетной записи пользователя. И в этом большая разница между токеном доступа и токеном обновления. Чтобы отозвать выданный токен обновления, сервер должен сохранить все выданные токены обновления. Другими словами, токен обновления сохраняет состояние. Серверу необходимо знать, какой из них действителен, какой недействителен.

Чтобы правильно реализовать токен обновления, нам нужно какое-то хранилище токенов для сохранения токена обновления. Также нам нужно реализовать как минимум три потока:

Обновить проверку токена
Обновить токен доступа с действительным токеном обновления
Отозвать скомпрометированный токен обновления пользователя

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

Выше мое текущее понимание того, как реализовать токен обновления. Это непросто, но создать более безопасную систему определенно необходимо.

Оказывается, в Feathers уже встроены все функции / модули, необходимые для правильной реализации токенов обновления:

  1. Хранилище токенов обновления: может легко поддерживаться сервисом Feathers.
  2. Выпуск и проверка токена обновления: можно просто повторно использовать существующую поддержку JWT, которая встроена в AuthenticationService.

Основываясь на работе, проделанной TheSinding (https://github.com/TheSinding/authentication-refresh-token), я реализовал свою собственную версию токенов обновления с одной настраиваемой службой и тремя хуками (https://github.com/ jackywxd / Feathers-refresh-token), который включает основные функции обновления токенов:

  1. Выпустить токен обновления после успешной аутентификации пользователя;
  2. Обновить токен доступа с действующим токеном обновления JWT;
  3. Выйти из системы, удалив токен обновления

Несмотря на полное использование существующей кодовой базы в Feathres, на самом деле усилия по кодированию минимальны, и он прекрасно интегрируется с текущей архитектурой Feathers. Это доказывает, что нынешняя архитектура Feathers очень расширяема.

Но полная функция Refresh-token также требует поддержки на стороне клиента, такой как сохранение токена обновления на стороне клиента, повторная аутентификация пользователя после истечения срока действия токена доступа, выход пользователя из системы с помощью токена обновления.

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

Я уже перенес свою базу кода обновления токена версии хуков в @ Feesjs / authentication. Затем я бы попытался внести изменения в клиент аутентификации, чтобы включить функции на стороне клиента. Моя конечная цель - включить поддержку токенов обновления как на стороне сервера, так и на стороне клиента.

Мой вопрос / беспокойство заключается в том, как токен обновления будет храниться в клиенте?

См. Https://auth0.com/blog/securing-single-page-applications-with-refresh-token-rotation/

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

См. Https://afteracademy.com/blog/implement-json-web-token-jwt-authentication-using-access-token-and-refresh-token

Итак, как лучше всего безопасно хранить токены? Вы можете прочитать об этом больше в Интернете, если вы хотите добиться полностью безопасного хранения. Некоторые решения идеальны, но не очень практичны. Практически я бы сохранил его в файлах cookie с флагами httpOnly и Secure. Это не на 100 процентов безопасно, но выполняет свою работу.

См. Это длинное обсуждение файлов cookie - https://github.com/feathersjs-ecosystem/authentication/issues/132 тоже

@bwgjoseph Я бы предложил использовать обычный экспресс-сеанс и хранить все токены там, а не на стороне клиента. Это то, что я делаю, и отлично работаю со всеми типами приложений, включая SPA.

@sarkistlt Вы хотите сказать, что весь клиентский токен JWT хранится на стороне сервера? Есть ссылки / статьи по этому поводу? Я не совсем уверен, как будет выглядеть этот процесс. Так что же отправляет клиент, когда запрашивает данные (CRUD)?

@bwgjoseph как всегда, cookie, просто добавьте middlewere перед регистрацией ваших сервисов:

app.use('* | [or specific rout]', session(sess), (req, res, next) => {
      req.feathers.session = req.session || {};
      next();
    });

затем на вашем сервере, например, служба входа в систему, когда клиент аутентифицирован, вы просто сохраняете токен в сеансе, например ctx.params.session.token = token , где токен - это ваш JWT-доступ или токен обновления, зависит от логики вашего приложения.
И с любым новым запросом от клиента вы проверяете, существует ли токен в сеансе, и будете использовать его для аутентификации. Это гораздо более безопасный и безопасный подход, поскольку ни один из токенов вообще не отображается на стороне клиента.

Я просто добавлю, что это лучше всего работает для клиентских (браузерных) серверных приложений. При внутренней связи между серверами или рабочим / сервером сеанс не требуется.

Это обсуждалось _ много_ раньше (я также добавил запись в FAQ ), и не обязательно более безопасно хранить токен в сеансе. Если кто-то получает доступ к вашей странице, чтобы иметь возможность выполнять сценарии, он также захватил сеанс и в любом случае может выполнять аутентифицированные запросы.

Следовательно, обычно нормально хранить токен, например, в localStorage (к которому также имеет доступ только текущая страница), и он также легко работает с другими небраузерными платформами (такими как собственные мобильные приложения, сервер-сервер и т. Д.) __ и websockets__ (я не могу не подчеркнуть, насколько болезненно заставить веб-узлы работать без проблем и безопасно с HTTP-файлами cookie - моя жизнь стала намного проще с тех пор, как мы перестали пытаться это сделать). В общем, токен обновления должен быть отзывным, поскольку он обычно намного более долговечен.

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

@jackywxd - Отличная работа, я
Есть ли способ сделать это проще для разработчика?
Как интегрировать хуки, которые вы создали, в библиотеку, чтобы нам не нужно было добавлять хуки позже?

Я думаю, вам следует создать пул-реквест, и мы могли бы обсудить это.

@daffl да согласен, особенно с WS. И если вы или ваша команда создаете и клиент, и серверную часть, да, лучше всего просто использовать JWT и избежать дополнительных зависимостей и сложности в вашем приложении.
Но в некоторых случаях, например, при создании REST-API витрины, который будет использоваться сторонними компаниями / разработчиками, проще использовать обычный сеанс и просить разработчиков включать учетные данные в свои запросы, а затем описывать, как получить доступ (и обновить ) токены, сохраните их и передайте с каждым запросом. Что отлично обрабатывается клиентом пера, но в большинстве случаев, когда разработчик не знаком с тем, как построен бэкэнд, он будет использовать request, superagent, fetch or axios для подключения своего приложения к бэкэнду. По крайней мере, в моем случае это была основная причина перенести часть API витрины для работы с обычными сеансами, а не напрямую с JWT.

Но разве это не дизайнерское решение и ответственность создателя витрины - реализовать его в собственном API, а затем должным образом задокументировать эту функцию, вместо того, чтобы «навязывать» это решение сообществу?

@TheSinding Я думаю, что мы можем сказать «принуждение» о менее часто используемом подходе, а не о файлах cookie, которые были (и остаются) наиболее часто используемым подходом для управления сеансами пользователей.

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

Опять же, чтобы быть ясным, использование JWT - это здорово, и его проще использовать, особенно для API реального времени, и это то, что мы используем в 90% случаев + вам не нужно запускать redis или что-то еще для управления сеансами cookie.
Но есть некоторые исключительные случаи, когда это может быть не лучший выбор, я привел пример этой ситуации в своем предыдущем комментарии.

Я не говорил, что ты ошибаешься, я просто думал «вслух» :)

IMO, я думаю, что подход с JWT был бы лучшим подходом, поскольку это то, что уже поддерживается, и как @daffl также легче работать с

Спасибо за все ваши отзывы! JWT vs session - это отдельная тема, которую мы можем обсудить отдельно.

Я думаю, мы все согласны с тем, что токен доступа + токен обновления - гораздо более безопасное решение, чем просто токен доступа. Он был широко принят крупными интернет-гигантами. Справедливо сказать, что сообщество Feathers хотело бы увидеть основную базу кода Feathers для обеспечения встроенной поддержки токена обновления. На самом деле меня удивило, когда я впервые понял, что Feathers не поддерживает токен обновления.

Я использую AWSognito в нескольких своих проектах, AWS Amplify сохранит три токена в localStorage: токен ID, токен доступа и токен обновления, Amplify обрабатывает все грязные работы, связанные с управлением токенами, и предоставляет несколько API-интерфейсов, которые позволяют легко и просто. простой интерфейс, работающий с бэкэндом Cognito. Хотелось бы увидеть аналогичный опыт разработки с Feathers.

@TheSinding Спасибо за вашу предыдущую отличную работу!

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

this.hooks({ after: { create: [issueRefreshToken(), connection('login'), event('login')], remove: [logoutUser(), connection('logout'), event('logout')], patch: [refreshAccessToken()], },

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

@daffl Дэвид, спасибо за создание Feathers! просто интересно, есть ли какое-нибудь «руководство», «руководство по кодированию», «руководство по стилю» для Feathers?

Как я упоминал ранее, PR с реализацией токенов обновления (или даже просто некоторых идей) был бы очень кстати. У меня еще не было возможности проверить связанные репозитории, и это обсуждение становится довольно длинным. Если бы все это было обновлено и собрано в одном месте, это значительно упростило бы задачу. Некоторые важные пункты списка:

  • Жетоны обновления могут быть выпущены путем расширения службы аутентификации.
  • Токены обновления должны храниться в localStorage.
  • Токены обновления должны быть отзывными (поэтому должна быть более универсальная реализация механизма отзыва, описанного в https://docs.feathersjs.com/cookbook/authentication/revoke-jwt.html)
  • Из-за дополнительной сложности и настройки (например, Redis для хранения отозванных токенов) он может быть доступен как функция, но не должен быть включен по умолчанию (т. Е. Стандартное сгенерированное приложение - может быть частью интерфейса командной строки, но прежде чем делать что-либо с этим, Мне все еще очень нужна помощь в запуске генератора на основе гигена )
  • Информацию об участии можно найти в

Если кто-то использует refreshToken, мы создаем библиотеку, которая обрабатывает в интерфейсе, accessToken и refreshToken как «сеансы», слишком простая в использовании.

Нужно только передать токены, и библиотека попытается получить новый acessToken с refreshToken, когда истечет срок его действия. В настоящее время используется в г. Видеск .

Репозиторий: Front Auth Handler

Была ли эта страница полезной?
0 / 5 - 0 рейтинги