Безопасно ли в OAuth2 «Учетные данные пароля владельца ресурса»? - PullRequest
0 голосов
/ 04 ноября 2019

Итак, я разрабатываю API , используя slim/slim и league/oauth2-server для управления OAuth2 . OAuth2 будет полезен, потому что мне нужно будет использовать Предоставление клиентских учетных данных между сервисами.

Затем я также разрабатываю гибридное приложение с React Native . Это приложение требует входа пользователя в систему с использованием электронной почты и пароля или подключения к другим службам (таким как Facebook, Google, Twitter и т. Д.).

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

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

Поток, который я представляю, таков:что-то вроде этого:

  1. Пользователь открывает приложение, затем вводит свои учетные данные username и password;
  2. Этот экран подключится к API /request_token Отправка URI { 'grant_type': 'password', 'username': username, 'password': password, 'client_id': CLIENT_ID }рассматривая его как общедоступное приложение, мы не можем отправить client_secret;
  3. API проверяет учетные данные и возвращает некоторые данные, такие как { "access_token": access_token, "token_type": "JWT", "expires_in": LIFE_SPAN }, здесь мы будем использовать JWT , чтобы гееренироватьaccess_token на основе public/private key;
  4. Аутентификация завершена, приложение будет хранить access_token, пока оно живое, а по истечении этого срока будет передавать refresh_token.

Мой вопрос: это безопасно? Скотт Брэди сделал какую-то "агрессивную" статью, в которой говорилось, что она НИКОГДА не безопасна .

Как приложения это делают? Когда я использую приложение Instagram, например, они владеют приложением и API, мне не нужен браузер в потоке взаимодействия с пользователем. Используются ли в современных приложениях «Учетные данные пароля владельца ресурса» или «Код аутентификации с помощью PKCE»? Есть ли возможность избежать вставки браузера в поток при использовании «Аутентификационного кода с PKCE»?

[EDIT] Возможное решение

Как сказал Гари Арчер "Код авторизации"рекомендуется работать с PKCE - вместе с входом в систему через системный браузер ", но мы не говорим о предоставлении разрешений для доступа к данным пользователей или сторонним приложениям.

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

Что я сделаю, это создаю собственную версию кода аутентификации с помощью PKCEудаление required_uri.

[РЕДАКТИРОВАТЬ: 2] Новый поток

После долгих поисков я нашел несколько ответов, которые я думаю, было бы интересно адаптировать. Как и выше, я удалил redirect_url из потока. Смотрите:

  1. Поток запускается на экране входа в систему, когда пользователь вводит ваши учетные данные;
  2. Клиент генерирует code_verifier, затем хэширует code_verifier до code_challenge иотправляет его на сервер авторизации со следующими параметрами:

    • response_type=code: указывает, что ваш сервер ожидает получить код авторизации.
    • client_id=xxxx: идентификатор клиента.
    • client_integrity=xxxx: проверка целостности приложения для собственного приложения.
    • code_challenge=xxxx: вызов кода, сгенерированный, как описано выше.
    • code_challenge_method=S256: обычный или S256, в зависимости отот того, является ли вызов простой строкой верификатора или хешем SHA256 строки. Если этот параметр пропущен, сервер примет простое значение.
    • username=xxxx: имя пользователя для аутентификации.
    • password=xxxx: хешированная версия пароля.
    • state=xxxx: случайная строка, сгенерированная вашим приложением (защита CSRF).
  3. Сервер авторизации проверит аутентификацию пользователя, сохранит code_challenge и возвратит authorization_code с client_token;

  4. После получения aauthorization_code и client_token Клиент сохраняет client_token и немедленно отправляет authorization_code обратно на Сервер авторизации со следующими параметрами:

    • grant_type=authorization_code:указывает тип предоставления этого запроса токена.
    • code=xxxx: клиент отправит полученный код авторизации.
    • client_id=xxxx: идентификатор клиента.
    • code_verifier=xxxx: верификатор кода для запроса PKCE, который клиент изначально сгенерировал перед запросом авторизации.
  5. Сервер авторизации проверит все данные и, если все правильно, выполнитверните access_token;

  6. Клиент установит заголовок авторизации с access_token и всегда отправляет client_token на каждый запрос, он будет принят только с обоими правильными значениями;
  7. Если срок действия access_token истекает, то Клиент выполнит запрос на обновление access_token и получит новый.

Теперь я воспроизведу эту логику на языке PHP. Если все пойдет хорошо, и я надеюсь, что это произойдет, я вернусь с окончательным ответом.

[РЕДАКТИРОВАТЬ] Уточнения

Я использую OAuth2 для подключения пользователя к сторонним аккаунтам (Google, Facebook и т. д.). Но пользователь также может войти в локальную учетную запись в моей базе данных. В этом случае пользователю вообще не нужно ничего предоставлять. Так что, нет смысла отправлять пользователю в браузер, чтобы он делал свой логин.

Интересно, можно ли в этом случае использовать локальные учетные записи Учетные данные для пароля владельца ресурса или это более безопасно Код аутентификации с помощью PKCE (мы уже заключаем, что этолучше подойдет). Но для кода аутентификации с PKCE требуется redirect_uri. Нужно ли использовать это перенаправление для входа пользователей в локальную учетную запись, где им не нужно предоставлять доступ?

Ответы [ 3 ]

1 голос
/ 06 ноября 2019

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

В вашем сценарии вам необходимо обеспечить социальный вход (например: - Войти через Google, facebook). Это, конечно, желаемая функциональность, которую нужно поддерживать. Но это не ограничивает вас от получения учетных данных конечного пользователя через пользовательский процесс регистрации. Для этого есть много причин, например, не все используют социальные сети или учетную запись Google. И некоторые люди предпочитают регистрироваться, чем делиться идентификатором пользователя какой-либо другой службы (да, это противоположный конец социального входа в систему).

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

1 голос
/ 04 ноября 2019

Рекомендуется поток кода аутентификации с PKCE - вместе с входом в систему через системный браузер. Также рекомендуется шаблон AppAuth. https://curity.io/resources/develop/sso/sso-for-mobile-apps-with-openid-connect/

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

Если это поможет, вот несколько заметок для моего демонстрационного приложения для Android, которое также фокусируется на удобстве использования - и ссылки на пример кода, который вы можете запустить: https://authguidance.com/2019/09/13/android-code-sample-overview/

0 голосов
/ 08 ноября 2019

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

  • Вы никогда не должны доверять клиентам, работающим на стороне клиента. Существует множество проблем, связанных с тем, что ваши приложения могут быть декомпилированы, изменены, пользовательские устройства могут быть подвержены вредоносным программам, или соединение может пострадать от атакующего человека в середине (MITM) ...
  • Сервер API,даже используя OAuth2, вы сможете определить только WHO , который обращается к ресурсам, но не WHAT . Поэтому любая конфиденциальная информация будет опасной, ее может украсть и использовать что угодно.
  • Учетные данные для пароля владельца ресурса является частью протокола OAuth2, позволяющего владельцу ресурса получить доступ к вашим ресурсам. Таким образом, он не является частью процесса аутентификации, и вы потерпите крах, если будете так обращаться;
  • Используя тип предоставления ROPC, невозможно узнать, действительно ли владелец ресурса делает этот запрос, чтосделать «легкую» фишинговую атаку. Напоминает о "вы знаете ВОЗ , а не ЧТО ". Наконец, этот тип предоставления облегчает любую вещь, которая предполагает идентификацию пользователя;
  • Этот тип предоставления также идет вразрез с OAuth2, поскольку OAuth стремится избежать использования пароля для доступа к ресурсам. Вот почему многие люди говорят, что не использовать его;
  • Для усиления важно подчеркнуть, что ROPC не аутентифицирует пользователя, а просто разрешает ему доступ к серверу ресурсов.
  • И даROPC позволяет обновлять токены, но есть две проблемы: во-первых, клиенту необходимо каждый раз вводить учетные данные для получения нового токена;во-вторых, при использовании долгосрочного кода доступа все становится более опасным.

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

Именно поэтому рекомендуется использовать в современных приложениях код аутентификации с PKCE , он обеспечивает все функции и преимущества использования протокола OAuth2. Но здесь идет долгое обсуждение и даже проблема для сообщества разработчиков:

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

Этот сценарий работает хорошо и NEEDS для использования в сторонних приложениях. Но что, если это приложение от первого лица? Когда у вас есть база данных с пользовательскими данными и у вас есть «доверенное» приложение, перенаправление пользователя не имеет никакого смысла. Правильно?

В данный момент мой вопрос: как я могу использовать поток AuthCode (PKCE) без перенаправления пользователя? И, опять же, важно подчеркнуть, что говорить о протоколе OAuth2 всегда одно и то же, что «предоставлять клиенту доступ к серверу ресурсов» (авторизация, а не аутентификация).

Поэтому реальный вопрос: зачем нужен код авторизацииперенаправление вообще? Затем я получил следующий ответ:

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

Вот почему я ошибся вмои правкиВ протоколе OAuth2 не требуется никаких изменений (извините, что я думаю иначе). По этой причине OAuth2 нужен посредник авторизации над вашим уровнем. Таким образом, код авторизации возвращается не клиенту, а посреднику авторизации, который, наконец, вернет его клиенту. Имеет смысл?

Как это сработает? Что ж, понадобятся 4 разных «ядра»:

  1. Сервер аутентификации : будет отвечать за аутентификацию учетных данных пользователя и идентификационных данных клиента. Основная цель - доказать, что « WHO является пользователем, а WHAT подключается для проверки подлинности»;
  2. Посредник авторизации (на один уровень выше OAuth2): проверяет уникальную идентификацию клиента, чтобы убедиться, что клиент / пользователь "знает" и может получить маркер доступа;
  3. Сервер авторизации: является частью реализации OAuth2, ничего не меняется. Авторизует клиента на получение вашего кода авторизации, доступ к токенам, токены обновления;
  4. Сервер ресурсов : разрешит доступ к ресурсам через токен доступа.

Изатем, методы безопасности, которые мы можем рассмотреть:

  1. Ключ API : каждое приложение (клиент) будет иметь свой собственный Ключ API с областями разрешений, связанными с этими ключами. Используя его, вы можете собрать основную статистику об использовании API. Большинство API-сервисов используют статистику для обеспечения ограничений скорости для каждого приложения, чтобы предоставлять различные уровни обслуживания или отклонять подозрительно высокочастотные шаблоны вызовов;
  2. Взаимная аутентификация SSL : с помощью этого метода клиент и сервер обмениваются ипроверять открытые ключи друг друга. Как только ключи проверены, клиент и сервер согласовывают общий секретный код, код аутентификации сообщения (MAC) и алгоритмы шифрования;
  3. HMAC : ключ API будет разделен на идентификатор иподелился секретом. Затем, как и прежде, идентификатор передается с каждым HTTP-запросом, но общий секрет используется для подписи, проверки и / или шифрования передаваемой информации. Клиент и сервер будут обмениваться общим секретом с алгоритмом, таким как HMAC SHA-256;
  4. Защита кода приложения : использование обфускаторов кода затруднит поиск и извлечение конфиденциальных данных из приложения, напримеркак секретный общий доступ, ключи API, открытые ключи ...
  5. Обработка учетных данных пользователя : предоставление простого способа входа пользователя в систему и подтверждения вашей личности. После вставки действительных учетных данных сервер может вернуть токен пользователя (JWT) и эмулировать с ним сеанс пользователя.

Давайте рассмотрим поток:

  • Часть первая: аутентификация пользователя и клиента;

    1. Пользователь введет ваши учетные данные и попросит подтвердить вашу личность, используя ваш адрес электронной почты или номер мобильного телефона, после того как Клиент отправит учетные данные пользователя (например, { email, mobile_number, hash ( password ), verification_method }) наСервер аутентификации по маршруту /login;
    2. Сервер аутентификации проверит учетные данные пользователя и отправит одноразовый пароль пользователю для подтверждения вашей личности (для электронной почты или номера мобильного телефона по выбору пользователя);
    3. Затем пользователь вставит полученный OTP, и клиент отправит обратно на сервер аутентификации по маршруту /login-otp, включая метод проверки (например, { otp, verification_method });
    4. В конце сервер аутентификации вернет { hash ( shared_secret ) } будет использоваться в ближайшее время.
  • Часть вторая: авторизация доступа к API;

    1. При получении shared_secret Клиент будет безопасно хранить на мобильном телефоне app, затем он запросит код авторизации, используя PKCE, вызывая /auth с { response_type, client_id, scope, state, code_challenge, code_challenge_method }, Сервер авторизации проверит учетные данные и вернет код авторизации без перенаправлений;
    2. Позже, Клиент будет обмениваться полученным кодом сТокен доступа обращается к /token, но для этого потребуется отправить некоторые дополнительные данные: { payload: { grant_type, code, client_id, code_verifier }, timestamp, hash ( some_user_data + timestamp + shared_secret ) };
    3. Посредник авторизации получит этот запрос и подтвердит попытку создания того же хеша, сгенерированного пользователем. И перенаправить все данные на сервер авторизации, который будет проверять client_id, code и code_verifier, отвечая маркером доступа;
    4. Этот новый access_token вернется в посредник авторизации и, после этого, к предоставлению клиентудоступ к ресурсам API.
  • Часть третья: доступ к серверу ресурсов;

    1. Клиенту каждый раз требуется отправлять вызов API /api, содержащийзаголовок Authorization и некоторые дополнительные данные с { timestamp, hash ( some_user_data + timestamp + shared_secret ) };
    2. Посредник авторизации проверит хэши shared_secret, вызовет Resource Server для проверки access_token и вернет данные.
  • Часть четвертая: обновление токена доступа;

    1. После истечения срока действия маркера доступа Клиент отправит вызов на /refresh-token, содержащий заголовок Authorization и некоторые дополнительные данные с { payload: { grant_type, refresh_token, client_id, scope }, timestamp, hash ( some_user_data + timestamp + shared_secret ) };
    2. Посредник авторизации проверит хэши shared_secret, вызовите Сервер авторизациии верните новый доступ к новому токену.

Визуальное изображение для этого потока:

User App Login Flow

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

Некоторые ссылки и поддержка:

Как популярноприложения аутентифицируют запросы пользователей из своего мобильного приложения на свой сервер?

Зачем вашему мобильному приложению нужен ключ API?

Методы обеспечения безопасности мобильного API

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

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