Обработка обновления токена / истечения сеанса в RESTful API

17

Я создаю RESTful API, который использует токены JWT для аутентификации пользователя (выпущенные loginконечной точкой и отправленные во всех заголовках впоследствии), и токены необходимо обновить через фиксированное время (вызывая renewконечную точку, которая возвращает обновленный токен ).

Возможно, что сеанс API пользователя становится недействительным до истечения срока действия токена, поэтому все мои конечные точки начинаются с проверки того, что: 1) токен все еще действителен и 2) сеанс пользователя все еще действителен. Нет возможности напрямую аннулировать токен, потому что клиенты хранят его локально.

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

  1. Верните код http 401 (неавторизованный), если сеанс стал недействительным, или верните код 412 (предварительное условие не выполнено), когда токен истек, и пришло время вызвать renewконечную точку, которая вернет код 200 (ok).
  2. Возврат 401 для сигнализации о том, что либо сеанс недействителен, либо токен истек. В этом случае клиент немедленно вызовет renewконечную точку, если он возвращает 200, то токен обновляется, но если renewтакже возвращается 401, то это означает, что клиент находится вне системы.

Какой из двух вышеуказанных вариантов вы бы порекомендовали? Какой из них будет более стандартным, более простым для понимания и / или более RESTful? Или вы бы порекомендовали другой подход вообще? Видите ли вы какие-либо очевидные проблемы или угрозы безопасности с любым из вариантов? Дополнительные баллы, если ваш ответ включает внешние ссылки, которые поддерживают ваше мнение.

ОБНОВИТЬ

Ребята, пожалуйста, обратите внимание на реальный вопрос - какой из двух вариантов кода http для сигнализации о возобновлении / аннулировании сессии является лучшим? Не берите в голову тот факт, что моя система использует JWT и сеансы на стороне сервера, это особенность моего API для очень специфических бизнес-правил, а не та часть, для которой я ищу помощь;)

Оскар Лопес
источник
Как сеанс пользователя станет недействительным до истечения срока действия токена при условии короткого (около 5 минут) срока действия?
Джек,
Из-за бизнес-правила другая часть системы может сделать сеанс недействительным.
Оскар Лопес
1
JWT предназначены для подтверждения личности, так как «этот запрос подтвержден пользователем X». Если ваше бизнес-правило выглядит так: «Пользователю X больше не разрешено взаимодействовать с ресурсом Y», это следует проверять отдельно от JWT.
Джек,
@ Джек точно! это моя точка зрения и причина, по которой мне нужно использовать дополнительный слой с сохранением состояния для сохранения информации о сеансе. Простой JWT, каким бы красивым он ни был, просто не подходит для работы.
Оскар Лопес
1
Вы можете быть заинтересованы в моем ответе тогда :)
Джек

Ответы:

22

Это звучит как случай аутентификации против авторизации .

JWT - это криптографически подписанные заявления об отправителе запроса. JWT может содержать утверждения типа «Этот запрос предназначен для пользователя X» и «Пользователь X имеет роли администратора». Получение и предоставление этого доказательства с помощью паролей, подписей и TLS является областью аутентификации - доказательство того, кем вы являетесь.

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

Сценарий А - Аутентификация

  • Боб: «Привет, Джим, я хотел бы войти в ограниченное хранилище».
  • Джим: "У тебя есть свой значок?"
  • Боб: Нет, забыл это.
  • Джим: «Извини, приятель, вход без пропуска».

Сценарий B - Авторизация

  • Боб: «Привет, Джим, я хотел бы войти в ограниченное хранилище. Вот мой значок».
  • Джим: «Привет, Боб, тебе нужно разрешение 2 уровня, чтобы войти сюда. Извини».

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

Эти два случая имеют разные коды ответов HTTP: 401 Unauthorizedи 403 Forbidden. К сожалению, названный код 401 предназначен для проблем аутентификации, таких как отсутствующие, просроченные или аннулированные учетные данные. 403 для авторизации, когда сервер точно знает, кто вы, но вам просто не разрешено делать то, что вы пытаетесь сделать. В случае удаления учетной записи пользователя попытка что-либо сделать с JWT в конечной точке приведет к ответу 403 Запрещено. Однако, если срок действия JWT истек, правильный результат будет 401 Unauthorized.

Распространенный шаблон JWT - иметь «долгоживущие» и «недолговечные» токены. Долгоживущие токены хранятся на клиенте как краткосрочные токены, но они ограничены по объему и используются только с вашей системой авторизации для получения краткосрочных токенов. Долгоживущие токены, как следует из названия, имеют очень большой срок действия - вы можете использовать их для запроса новых токенов в течение нескольких дней или недель подряд. Краткосрочные токены - это токены, которые вы описываете и используются с очень коротким сроком действия для взаимодействия с вашей системой. Долгоживущие токены полезны для реализации функциональности Remember Me, поэтому вам не нужно вводить пароль каждые пять минут, чтобы получить новый краткосрочный токен.

Проблема «аннулирования сеанса», которую вы описываете, похожа на попытку аннулировать долгоживущий JWT, поскольку недолговечные редко сохраняются на стороне сервера, а долгоживущие отслеживаются на случай, если их нужно отозвать. В такой системе попытка получить учетные данные с помощью аннулированного долгоживущего токена приведет к 401 несанкционированному доступу, поскольку технически пользователь может получить учетные данные, но используемый ими токен не подходит для этой задачи. Затем, когда пользователь пытается получить новый долгоживущий токен, используя свое имя пользователя и пароль, система может ответить 403 Запрещено, если его выгнали из системы.

разъем
источник
3
Это руководство, которое я искал, и вы привнесли в дискуссию очень важную информацию - это случай аутентификации и авторизации, и каждый из них должен рассматриваться по-разному. Благодарность!
Оскар Лопес
16

Ваш сеанс API - это то, чего вообще не должно быть в мире RESTful. Предполагается, что операции RESTful не имеют состояния, сессия содержит состояние и, следовательно, не имеет места в мире RESTful.

JWT должен быть вашим единственным способом определить, имеет ли пользователь право на доступ к конечной точке или нет. Сессия не должна играть абсолютно никакой роли в этом. Если это так, у вас нет RESTful API.

Когда вы полностью исключаете сеанс, что, если вы стремитесь использовать RESTful API, и должны использовать только JWT в качестве фактора аутентификации, пользователь либо авторизуется использовать вашу конечную точку, либо нет - в этом случае 401 Unauthorizedкод ответа является подходящим - и должен позвонить renewконечной точке с grant_type=refresh_tokenили каким-либо другим идентификатором продления, которое вы используете.

Обновить:

Из комментария кажется, что поток проверки JWT, который вы используете в данный момент, неверен. Проверка должна выглядеть так:

  Client        RESTful API      JWT Issuer
     |              |                |
     |----- 1. ---->|                | 
     |              |------ 2. ----->|-----
     |              |                | 3. |
     |              |<----- 4. ------|<----
-----|<---- 5. -----|                |
| 6. |              |                |
---->|----- 7. ---->|                |
     |              |------ 8. ----->|-----
     |              |                | 9. |
     |              |<----- 10. -----|<----
     |              |                |
     |              |------          |
     |              | 11. |          |
     |<---- 12. ----|<-----          |
     |              |                |
     .              .                .

1. Ask RESTful API for a JWT using login endpoint.
2. Ask Issuer to create a new JWT.
3. Create JWT.
4. Return JWT to the RESTful API.
5. Return JWT to Client.
6. Store JWT to append it to all future API requests.
7. Ask for data from API providing JWT as authorization.
8. Send JWT to Issuer for verification.
9. Issuer verifies JWT.
10. Issuer returns 200 OK, verification successful.
11. Retrieve and format data for Client.
12. Return data to Client.

Сервер RESTful APIдолжен проверить действительность токена, который отправляется в качестве Авторизации. Это не ответственность Client. Похоже, что вы в настоящее время не делаете этого. Внедрите проверку JWT таким образом, и вам вообще не понадобятся сеансы.

Энди
источник
Спасибо за Ваш ответ. Согласитесь, использование сеанса не будет подходом на 100% RESTful, но, как я упоминал выше, мне нужно запретить доступ некоторым пользователям до истечения срока действия токена.
Оскар Лопес
2
@ ÓscarLópez Затем просто аннулируйте токены, которые используют пользователи. Они больше не смогут получить доступ к API с помощью предоставленного токена (который теперь будет признан недействительным), и вам не нужен сеанс.
Энди
1
Токены хранятся на клиенте, как я могу сделать их там недействительными? Я должен был бы отследить, какие из них действительны ... и именно здесь государство поднимает свою уродливую голову. Иногда это неизбежно.
Оскар Лопес
Злонамеренный клиент может отправлять ранее действующий токен до тех пор, пока это позволяет время его истечения, но мне нужно немедленно выгнать его из системы - следовательно, установка короткого времени обновления также не вариант.
Оскар Лопес
4
@Laiv Я сделал диаграмму последовательности в блокноте.
Энди
1

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

С точки зрения REST, клиент либо аутентифицирован, либо нет. Архитектура не заботится о том, почему (это впрыскивает ненужное состояние), поэтому, чтобы ответить на ваш главный вопрос, у меня вообще не будет обновленной конечной точки. Зарегистрированный клиент просто всегда отправляет свой JWT, и сервер всегда проверяет его и либо принимает, отправляя соответствующий код успеха на основе действия 200, 201 и т. Д.), Либо отклоняет его с помощью 401 или 403 в зависимости от ситуации.

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

Наконец, если вы утверждаете, что учетная запись может быть разблокирована и действительна, но JWT просто необходимо отозвать, то я ВСЕ ЕЩЕ придерживаюсь 401 или 403 и поддерживаю что-то вроде Списка отзыва сертификатов недействительных JWT, которые вы можете поместить в до тех пор, пока он очищается, когда истечет время JWT (у большинства баз данных есть способ сделать это, или у вас могут быть события в коде приложения).

Павел
источник
JWT предназначены для безгражданства. в тот момент, когда вы подвергаете сомнению его содержание и проверяете его по БД, он больше не является лицом без состояния, поэтому становится излишним, так как существуют лучшие решения для сеансов с
полным