Можно ли отправлять секрет клиента как одноразовый номер?

#api #oauth-2.0 #jwt #azure-active-directory #single-page-application

#API #oauth-2.0 #jwt #azure-active-directory #одностраничное приложение

Вопрос:

Я создаю SPA, который подключается к моему серверному API, и мне нужно интегрировать логин Azure AD, я немного смущен всем потоком авторизации. Я стараюсь быть как можно более защищенным. Я объясню этот процесс ниже:

  1. Я создаю URL-адрес в серверной части (содержащий идентификатор арендатора и другую информацию), который возвращается в SPA для добавления с помощью кнопки.
  2. Пользователь нажимает на кнопку, перенаправляется на страницу аутентификации Microsoft / Company.
  3. Если аутентификация прошла успешно, пользователь перенаправляется обратно в SPA вместе с идентификатором ID.
  4. SPA принимает токен ID и отправляет его в качестве токена-носителя при каждом запросе к API.
  5. API проверяет подпись, а затем проверяет некоторые утверждения токенов JWT (такие как aud, iss, exp и т.д.).

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

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

Это правильный способ сделать это? Из того, что я прочитал, вы можете использовать проверку и проверку подписи JWT ИЛИ метод идентификации клиента / секрет клиента, но почему я не могу использовать оба, как в моем примере, когда одноразовый номер является секретным.

Во-вторых, если я использую одноразовый номер для этого, для чего я должен использовать параметр состояния? Должен ли я создавать состояние как случайную строку, созданную SPA (то есть интерфейсом).

ОБНОВЛЕНИЕ: после дальнейшего чтения я понял, что вы НЕ МОЖЕТЕ использовать секрет клиента в качестве одноразового номера, потому что вся идея одноразового номера должна быть уникальной каждый раз. Одноразовый номер — это фактически слово, созданное и используемое только один раз, после чего оно отбрасывается. Поскольку секрет клиента всегда один и тот же, это не смягчит «повторные атаки».

Я сохраню этот пост, поскольку у меня все еще есть следующие вопросы:

  1. Используется ли одноразовый номер для проверки API / серверной части, а состояние используется клиентом / браузером (например, интерфейсом)?
  2. Что мне делать с секретом клиента? Кажется, сейчас это бесполезно. Должен ли я добавить его в качестве зашифрованного пользовательского утверждения?

ОКОНЧАТЕЛЬНОЕ ОБНОВЛЕНИЕ: помимо принятого ответа, пожалуйста, прочитайте о неявном потоке, потоке кода аутентификации, токенах идентификаторов и токенах доступа и разнице между ними, чтобы понять.

Ответ №1:

1. Не внедряйте протокол, используйте библиотеку

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

В вашем случае я бы рекомендовал использовать библиотеку аутентификации Microsoft для JavaScript (MSAL.js ). Быстрый запуск для MSAL.js это хорошее место для начала.

2. Для SPA используйте поток кода авторизации с помощью PKCE

Вы пытаетесь реализовать неявный поток предоставления из приложения JavaScript. Вместо этого вам следует переключиться на использование потока кода авторизации (с помощью PKCE). Чтобы сделать это правильно, вам нужно будет разобраться с «code verifier» и «code challenge» и выполнить некоторое хеширование. Вместо этого вы должны просто использовать библиотеку (см. # 1, выше).

Последняя версия MSAL.js реализует поток предоставления кода авторизации с помощью PKCE, и вам вообще не нужно иметь с этим дело.

3. Нет, не используйте секрет клиента в качестве одноразового номера.

(Редактирование было только что добавлено, поэтому я не буду вдаваться в подробности, почему нет.)

Используется ли одноразовый номер для проверки API / серверной части, а состояние используется клиентом / браузером (например, интерфейсом)?

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

Что мне делать с секретом клиента? Кажется, сейчас это бесполезно. Должен ли я добавить его в качестве зашифрованного пользовательского утверждения?

Нет, не делайте этого.

Для начала, ни одна часть вашего приложения на JavaScript не должна содержать в себе какой-либо долгосрочный секрет (например, секрет клиента). Помните, что любой, кто может загрузить приложение, может просмотреть код вашего приложения и увидеть весь трафик между вашим приложением и любым вызываемым им внутренним сервером. Если это сообщение содержит секрет, то любой пользователь вашего приложения может увидеть этот секрет.

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

Комментарии:

1. Спасибо за ответ, но я в замешательстве. 1. Я не хотел использовать MSAL, потому что думал, что это библиотека, которая обрабатывает аутентификацию для страниц без серверной части, и когда я имею в виду серверную часть, я имею в виду API. Возможно, вы ссылаетесь на SPA, которые не вызывают никаких API, поэтому они должны полагаться на себя в части аутентификации. После прочтения о потоке аутентификации и неявном потоке это начинает иметь некоторый смысл. 2. Дело в том, что я регистрирую пользователей в серверной части с помощью токенов JWT, которые генерируются моим приложением. Я не понимаю, как объединить поток аутентификации с Azure и моими собственными пользователями.

2. Вы смотрели на quickstart, на который я ссылался в своем ответе? Здесь показано, как использовать MSAL, чтобы пользователь мог войти в систему, а затем получить токен доступа для вызова API. В приведенном примере API — это Microsoft Graph, но это также может быть ваш собственный API.

3. Да, прошу прощения, после прочтения quickstart и auth flow я лучше понимаю разницу между ними. Графическая часть сбивала меня с толку. И последний вопрос: в каком случае был бы полезен неявный поток?. Прямо сейчас кажется, что неявный поток был старым способом ведения дел и устарел, а поток кода аутентификации является более новым и более безопасным. Это правильно?