Как защитить REST API только для надежных мобильных приложений

96

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

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

Есть ли способ сделать это?

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

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

Обновление 2: кажется, что есть несколько ответов на этот вопрос, но я, честно говоря, не знаю, какой из них помечать как ответ. Некоторые говорят, что это может быть сделано, некоторые говорят, что это невозможно.

Supercell
источник
HTTPS использует SSL (и TLS). SSL / TLS может использоваться с аутентификацией клиента.
atk
Вы имеете в виду клиентские SSL-сертификаты? Я думаю, что это то, что я ищу, за исключением того, что я понятия не имею, возможно ли это даже в мобильных приложениях (Android и iOS)? Где будет храниться сертификат клиента? Память устройства, память?
Supercell
SSL будет сертифицировать только мобильное устройство, а не мобильное приложение.
дебилы
@Supercell: Я добавлю ответ
atk

Ответы:

48

Вы не можете

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

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

Это то же самое, что и проверка клиента. Вы можете проверить только поведение Клиента, но не самого Клиента.

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

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

См. Также: Отказ от проверки SSL-сертификатов для приложений Android

и: Насколько безопасны клиентские SSL-сертификаты в мобильном приложении?

Идиоты
источник
1
Я использовал клиентские сертификаты на оборудовании, где сертификат хранился на диске, зашифрованном операционной системой. Но даже там никто не верил, что это надежно. Цель состояла в том, чтобы сделать это простым для случайных пользователей.
Gort the Robot
1
@ Morons: веб-приложение решит эту проблему, но мы думаем, что пользователи с большей вероятностью будут использовать нативное приложение, чем веб-приложение (пожалуйста, исправьте меня, если наше предположение неверно). Причина, по которой это так важно, заключается в том, что API предоставляет пользователю доступ к частям нашей базы данных, которая содержит много данных, которые мы собрали за месяцы работы. Это данные, которые другие компании или пользователи могут легко использовать в своих целях. Без защиты клиентов мы бы не знали, кто их использовал (против нас).
Supercell
6
Веб-приложение не решает проблему. Это довольно тривиально изменить любой клиентский веб-приложение и заставить его делать все, что вы хотите.
Gort the Robot
5
@Supercell Вы не можете показывать кому-либо данные, а затем мешать им делиться ими. Если вы не хотите, чтобы у кого-то были Данные, вы не даете их (покажите) им.
дебилы
Я согласен, но по другой причине. Вы можете, если бы у вас был контроль над устройствами, например, rsa en.wikipedia.org/wiki/SecurID . Но мобильные телефоны не являются чем-то, что можно контролировать (они могут принимать вложения, такие как ключ плагина или что-то в этом роде).
imel96
31

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

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

В любом случае, общий подход:

  • Клиент содержит секрет
  • Делая запрос, он объединяет параметры запроса с секретами и хэширует результат
  • Этот хеш отправляется вместе с запросом и проверяется сервером

например, представьте GETзапрос на/products/widgets

Допустим, секрет клиента - "OH_HAI_I_IZ_SECRET"

Объедините HTTP-глагол, и URL, и секрет:

GET/products/widgetsOH_HAI_I_IZ_SECRET

И возьмите SHA-1 хэш этого:

4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

Затем отправьте это вместе, чтобы запрос был для:

GET /products/widgets?hash=4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

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

GET/products/widgetsOH_HAI_I_IZ_SECRET1384987891

Хеш что:

2774561d4e9eb37994d6d71e4f396b85af6cacd1

И отправить:

GET /products/widgets?time=1384987891&hash=2774561d4e9eb37994d6d71e4f396b85af6cacd1

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

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

Carson63000
источник
6
этот механизм хеширования может быть понят любым программистом, когда он разбирает apk.
Пунит Радж
8
@PunithRaj точно, я рассмотрел это во втором параграфе. «Ничто из того, что я собираюсь предложить, не позволит вам гарантировать, что кто-то не проведет реинжиниринг вашего клиента и не злоупотребит вашим REST API. Но это должно поставить барьер перед любыми случайными попытками».
Carson63000
для предупреждения я использую UTC на сервере и мобильном телефоне, это решает проблему, верно?
Шариф
@ Carson63000 - есть ли конкретное решение? особенно для API регистрации пользователей, который должен быть публично открытым (пользователь должен зарегистрироваться, прежде чем он сможет войти в систему, в Интернете или в мобильном приложении) и может быть направлен ботами для создания тысяч фальшивых пользователей.
Тохид
17

Всем, кто интересуется, на Android вы МОЖЕТЕ убедиться, что полученный вами запрос был отправлен из вашего приложения.

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

Процесс проверки проходит (ish) так:

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

полный блог, который объясняет это и как его реализовать, можно найти здесь: http://android-developers.blogspot.co.il/2013/01/verifying-back-end-calls-from-android.html

ndori
источник
1
Хороший ответ, однако злоумышленник все еще может подделать приложение с достаточными усилиями. но ничто не является по-настоящему безопасным, это не вопрос того, просто ли, когда вопрос
mateos
1
Для iOS есть такая опция: ссылка API-интерфейсы DeviceCheck также позволяют проверить, что полученный токен поступает с подлинного устройства Apple, на которое было загружено ваше приложение
Iwaz,
Требуются
5

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

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

Том Сквайрс
источник
5

Как отметил @Morons в своем ответе, очень сложно проверить сущность на другом конце соединения.

Самый простой способ обеспечить некоторый уровень аутентичности - заставить сервер проверить секрет, который знает только реальный объект. Для пользователя это может быть имя пользователя и пароль. Для программного обеспечения, в котором нет пользователя, вы можете встроить секрет.

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

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

Я работаю в компании под названием CriticalBlue (полное раскрытие!), У которой есть продукт под названием Approov, который пытается решить эту проблему доверия. В настоящее время он работает для Android / iOS и предоставляет механизм для проверки целостности клиентского приложения на наших серверах. Это достигается за счет того, что клиент рассчитывает ответ на случайный вызов. Клиент должен рассчитать ответ, используя атрибуты установленного пакета приложения, которые трудно подделать, и он включает в себя некоторые сложные механизмы предотвращения несанкционированного доступа.

Он возвращает токен, который вы затем можете отправить в качестве доказательства подлинности вашему API.

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

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

ThePragmatist
источник
0

SSL защитит канал связи.

Успешный вход в систему выдаст токен аутентификации по зашифрованному соединению.

Токен аутентификации будет передан вашему REST API во всех последующих запросах.

CodeART
источник
1
Я добавил дополнительную информацию. Я планировал сделать аутентификацию, как вы упомянули, с токеном доступа. REST API не требует, чтобы пользователь входил в систему, только для определенных действий. В обоих случаях клиенты должны быть подписаны / доверены.
Supercell
Я не знаю много о нативной мобильной разработке, но может ли ваше мобильное приложение предоставить номер мобильного телефона REST API? Когда я устанавливаю приложения на свой телефон Android, меня часто просят дать определенные разрешения приложению. Если вы можете отправить мобильный номер с каждым запросом через защищенное соединение, то вы можете отклонить все запросы с неизвестным номером мобильного телефона. Просто мысли здесь вслух ...
CodeART
Это может сработать, но для этого потребуется, чтобы пользователь вошел в систему и номер был привязан к учетной записи пользователя. В противном случае сервер не будет иметь ничего для проверки номера.
Supercell
Как вы собираетесь установить мобильное приложение?
CodeART
Они будут доступны через магазины приложений (Google, Apple, Microsoft)
Supercell
0

Это не будет слишком безопасно, но вы можете добавить какой-нибудь секретный код или даже подпись dgital. Недостаток: он должен быть включен в приложение, что облегчает его получение, если вы знаете, что делаете.

fNek
источник
0

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

Фактически, вы можете использовать SSL для аутентификации как клиента, так и сервера. Или, по-другому, «да, вы можете использовать клиентские сертификаты».

Вам нужно будет ...

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

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

атк
источник