Секреты OAuth в мобильных приложениях


137

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

Хранить строку в приложении явно нехорошо, так как кто-то может легко ее найти и злоупотребить ею.

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

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

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


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

Даже после того, как пользователь разрешил вам доступ к своей учетной записи (скажем, в Twitter), вы должны использовать секрет, полученный от службы, к которой вы пытаетесь получить доступ. Этот секрет используется во всех коммуникациях с их сервером, вместе с ключом аутентификации и некоторыми другими ключами. Так что да, вы можете хранить ключ доступа, но секрет не должен храниться, потому что его можно использовать с любым ключом аутентификации для злоупотребления службой. Опять же, я был бы рад, если бы меня поправили люди, которые знают об этом больше.
Феликсиз

1
OAuth предлагает метод аутентификации, который защищает данные для входа первоначального пользователя. Чтобы сделать это возможным, создается новая уникальная комбинация входа в систему, которая работает только вместе с уникальной комбинацией клавиш приложения. Большим преимуществом по сравнению с сохранением данных для входа пользователя является то, что они полностью безопасны после первой авторизации, и в любом случае пользователь может просто отозвать доступ авторизации. И, конечно, сохранение секрета не имело бы смысла, так как пользователь должен был бы затем повторно подтвердить подлинность (и это не то, что пользователь хочет, предоставляя доступ к приложению).
тыкай

@poke Ключ аутентификации, полученный при одобрении пользователем вашего приложения у провайдера, должен быть сохранен, но секретный токен, полученный вами от провайдера перед выпуском приложения, не должен (в случае настольного или мобильного приложения; если веб-приложение, которое вы можете хранить ключ на сервере, как указано в вопросе).
Феликсиз

4
Согласно моему пониманию oAuth-- В случае настольного приложения очень просто отследить / отслеживать трафик HTTP / HTTPS с помощью таких инструментов, как ieinspector.com/httpanalyzer/index.html Следовательно, ваш токен и секрет токена могут быть найдены очень без труда. Так что единственная защита - ваш потребительский секрет. Теперь, если ваш магазин хранит секрет внутри приложения, и кто-то может его найти, это становится детской игрой, выдавая себя за любое другое приложение в качестве вашего приложения. Поправь меня, если я ошибаюсь.
Варун

Ответы:


38

Да, это проблема дизайна OAuth, с которой мы сталкиваемся. Мы выбрали прокси все звонки через наш собственный сервер. OAuth не был полностью избавлен от настольных приложений. Нет префектного решения проблемы, которую я нашел, без изменения OAuth.

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

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

Я работаю над предложением системы делегирования для OAuth. Концепция заключается в том, что, используя наш собственный секретный ключ, который мы получаем от нашего провайдера, мы можем выдать наш собственный делегированный секрет нашим собственным настольным клиентам (в основном один для каждого настольного приложения), а затем во время процесса аутентификации мы отправляем этот ключ на верхний уровень. провайдер, который перезванивает нам и повторно подтверждает с нами. Таким образом, мы можем отозвать собственные секреты, которые мы выдаем каждому клиенту. (Занимать много, как это работает из SSL). Вся эта система будет идеально подходить для веб-сервисов с добавленной стоимостью, а также для передачи вызовов сторонним веб-сервисам.

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

Есть несколько разговоров о проблеме в Интернете:

http://blog.atebits.com/2009/02/fixing-oauth/ http://groups.google.com/group/twitter-development-talk/browse_thread/thread/629b03475a3d78a1/de1071bf4b820c14#de1071bf4b820c14

Решение Twitter и Yammer - это решение для аутентификации: https://dev.twitter.com/oauth/pin-based https://www.yammer.com/api_oauth_security_addendum.html


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

Как предложенная вами схема может помочь веб-службам с добавленной стоимостью, поскольку эта проблема к ним не относится? Кроме того, я не понимаю, как это будет работать с провайдером, генерирующим новые секреты, так как вам потребуется «главный секрет», чтобы даже запросить эти новые секреты, поэтому вам потребуется по крайней мере один вызов к вашему собственному серверу (который содержит главный секрет). Но это, конечно, лучше, чем маршрутизация всего трафика через ваш собственный сервер. Разъяснения приветствуются! И, пожалуйста, обновляйте здесь по мере продвижения вашего предложения!
Феликсиз

5
Просто любопытно: как определить, что звонящий на ваш прокси-сервер является законным?
davidtbernal

1
В ответ на notJim: основной риск, позволяющий раскрыть секрет вашего потребителя, заключается в том, что с его помощью могут быть разработаны вредоносные (или глупые) приложения, которые бросают тень на вашу репутацию и повышают риск того, что законное приложение будет закрыто из-за злоупотребления / неправильного использования API. Проксируя все вызовы, для которых требуется ваш секрет, через веб-приложение, которым вы управляете, вы возвращаетесь в положение, в котором вы можете отслеживать шаблоны злоупотреблений и отзывать доступ на уровне пользователя или токена доступа до того, как API, который вы используете, решит закрыть вниз весь ваш сервис.
квазистоил

Я согласен с квазистойкой здесь, вам нужно использовать браузер с поддержкой SSL для обработки вызовов oauth. Это хорошо по нескольким причинам, включая простое управление любыми обновлениями безопасности в будущем, и в реальном приложении ничего не потребуется обновлять с течением времени. Зак отмечает, что Твиттер предлагает решение с использованием PIN-кода, которое я тоже придумал, потому что вы не можете доверять приложению, чтобы безопасно получить код. Я предлагаю использовать «Nonce» с современным шифрованием вместе с PIN-кодом и секретом для прокси-запросов через веб-сервер.
Марк

18

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

В OAuth 1.0 (Twitter) секрет необходим для выполнения вызовов API. Прокси-вызовы через сервер - единственный способ убедиться, что секрет не взломан.

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

(Я редактор спецификации OAuth 2.0)


2
Можете ли вы рассказать о «механизме, специфичном для платформы, чтобы получить какой-нибудь идентификатор приложения»? Как серверный компонент для проверки личности клиента? Я думаю, что это можно сделать с помощью клиента. Например, разверните новый и уникальный сертификат SSL для каждого клиента. Это то, что вы имели ввиду? Если это сложнее, чем это, может быть, вы можете обратиться к более углубленной рецензии?
Cheeso

2
Я вспоминаю, как некоторые сотрудники службы безопасности говорили о том, как это можно сделать. Существует вызов ОС, который возвращает подписанный токен, который затем можно отправить на сервер и проверить. Извините, у меня нет подробностей. Это ошибка, которая может использовать несколько хороших примеров.
Дик Хардт

2
@DickHardt, но как в этом сценарии вы гарантируете, что мобильное приложение действительно является вашим приложением, а не мошенническим?
Рафаэль Мембривз

11

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

Это не надежное решение, а дешевое.

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


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

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

8
Запутывание не является безопасностью вообще. Это хуже, чем отсутствие безопасности вообще, потому что это дает разработчику ложное чувство безопасности. en.wikipedia.org/wiki/Security_through_obscurity
Пол Легато

8
«Запутывание не является безопасностью вообще. Это хуже, чем отсутствие безопасности вообще, потому что это дает разработчику ложное чувство безопасности». Ерунда. Никто не говорит, что запутывание способствует хорошей безопасности. Но если я собираюсь распространять секрет OAuth с моим apk, то, безусловно, лучше запутать, чем нет. Обфускация - это то, что Google также рекомендует при хранении ключей / секретов в приложении. Если ничего больше, эти меры держат случайных хакеров в страхе, что лучше, чем ничего. Общие утверждения, подобные вашей, приравнивают несовершенную безопасность к отсутствию безопасности. Это просто неправда. Несовершенный просто несовершенен.
Hungryghost

1
Запутывание НЕ помогает, потому что независимо от того, сколько вы делаете сдвигов или кодировок, вы все равно создаете ключ вместе и используете его для создания своего запроса API. Довольно просто динамически перехватить API в нужных местах, чтобы выгрузить отправляемый вами запрос даже до шифрования HTTPS. Поэтому, пожалуйста, не встраивайте секретные ключи в ваше приложение, если на самом деле нет никакой альтернативы.
C0deH4cker

6

Не храните секрет внутри приложения.

Вам нужно иметь сервер, к которому приложение может получить доступ через https (очевидно), и вы храните секрет на нем.

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

Затем, если вам нужно получить какую-либо конфиденциальную информацию от службы (facebook, google, twitter и т. Д.), Приложение запросит ваш сервер, и ваш сервер передаст ее приложению, только если оно правильно подключено.

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

Заметка

Тем не менее, это защитит вас только от злонамеренного клиента, но не клиента от злонамеренного вас и не клиента от других вредоносных клиентов (фишинг) ...

OAuth - намного лучший протокол в браузере, чем на настольном / мобильном.


1
разве это не облегчает жизнь хакеру ?! потому что теперь, чтобы получить доступ к ресурсам сервера, нам технически нужен идентификатор клиента, поскольку сервер все равно добавит секрет к запросу. я что-то упускаю?
Худи Ильфельд,

@HudiIlfeld Да, вы что-то упустили: клиент должен войти на сервер. Пока он не авторизован, сервер ничего не вернет. Один из способов справиться с этим - после первой отправки учетных данных сервер возвращает клиенту токен доступа, а затем клиент отправляет этот токен доступа при каждом последующем запросе. Здесь есть много вариантов.
Гудрадайн

4

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

PKCE (RFC 7636) - это метод защиты публичных клиентов, которые не используют секрет клиента.

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

с https://oauth.net/2/pkce/

Для получения дополнительной информации вы можете прочитать полный RFC 7636 или это краткое введение .


2

Вот о чем подумать. Google предлагает два метода OAuth ... для веб-приложений, где вы регистрируете домен и генерируете уникальный ключ, и для установленных приложений, в которых вы используете ключ «анонимный».

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


2

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

Хорошее описание того, как это реализовать, можно найти здесь: https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified#mobile-apps.


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

0

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

Я всегда думал, что намерение, стоящее за OAuth, заключается в том, чтобы каждый Том, Дик и Гарри, у которых было мэшап, не должны были хранить свои учетные данные Twitter в открытом виде. Я думаю, что это решает эту проблему довольно хорошо, несмотря на ее ограничения. Кроме того, он не был разработан специально для iPhone.


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

OAuth 1 требует подписания каждого запроса. OAuth 2 требует только токен доступа. Оба требуют ключ и секрет при получении токена.
Дик Хардт

0

Я согласен с Феликсом. Хотя OAuth лучше, чем Basic Auth, ему еще предстоит пройти долгий путь, чтобы стать хорошим решением для мобильных приложений. Я играл с использованием OAuth для аутентификации приложения для мобильного телефона в приложении Google App Engine. Тот факт, что вы не можете надежно управлять секретом пользователя на мобильном устройстве, означает, что по умолчанию используется анонимный доступ.

На этапе авторизации браузера OAuth в Google App Engine вы переходите на страницу, на которой содержится такой текст: «Сайт <some-site> запрашивает доступ к вашей учетной записи Google для продуктов, перечисленных ниже».

YourApp (yourapp.appspot.com) - не связан с Google

и т.д

Он берет <some-site> из имени домена / хоста, используемого в URL-адресе обратного вызова, который может быть любым в Android, если вы используете пользовательскую схему для перехвата обратного вызова. Таким образом, если вы используете «анонимный» доступ или ваш секрет потребителя скомпрометирован, тогда любой может написать потребителю, который обманет пользователя, предоставив доступ к вашему gae-приложению.

Страница авторизации Google OAuth также содержит много предупреждений, которые имеют 3 уровня серьезности, в зависимости от того, используете ли вы «анонимный», секретный ключ пользователя или открытые ключи.

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

Этот пост в блоге объясняет, как секреты пользователей не работают с установленными приложениями. http://hueniverse.com/2009/02/should-twitter-discontinue-their-basic-auth-api/


0

Я также пытаюсь найти решение для проверки подлинности OAuth для мобильных устройств и хранить секреты в комплекте приложений в целом.

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

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

Будет ли это работать?


3
Хорошая мысль, но нет. Взломщик просто увидит двоичный файл, указывающий на адрес постоянной ОС.
GrayB


0

Facebook не реализует OAuth, строго говоря (пока), но они реализовали способ, позволяющий вам не встраивать свой секрет в приложение для iPhone: https://web.archive.org/web/20091223092924/http://wiki. developers.facebook.com/index.php/Session_Proxy

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


1
wiki.developers.facebook.com мертв.
Хьюго

0

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

Одним из решений может быть наличие динамического секрета, который состоит из временной метки, зашифрованной с помощью частного ключа и алгоритма двустороннего шифрования. Затем служба расшифровывает секрет и определяет, является ли отметка времени +/- 5 минут.

Таким образом, даже если секрет будет раскрыт, хакер сможет использовать его не более 5 минут.


-2

Как уже упоминалось, не должно быть реальной проблемы с хранением секрета локально на устройстве.

Кроме того, вы всегда можете положиться на модель безопасности Android на основе UNIX: только ваше приложение может получить доступ к тому, что вы пишете в файловую систему. Просто запишите информацию в объект SharedPreferences вашего приложения по умолчанию.

Чтобы получить секрет, нужно получить root-доступ к телефону Android.


3
Как кто упомянул? Если вы имеете в виду комментарий poke, посмотрите мой ответ, что секрет! = Ключ аутентификации. Последний может безопасно храниться, первый не может. Я не знаю об Android, но получить root-доступ к iPhone совсем не сложно. Обратите внимание, что секрет одинаков во всех экземплярах приложения, поэтому злоумышленнику потребуется получить доступ только к одному двоичному файлу. И даже если они не могут получить root-доступ на устройстве, они могут получить двоичный файл в другом и извлечь из него секретный токен.
Феликсиз

1
просто добавьте, что очень легко получить root
права на
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.