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

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

Теперь у меня все работает через API. мои пользователи могут регистрироваться, искать компании, заказывать товары у этих компаний и отслеживать их заказы. Он еще неактивен, но он работает.

Я столкнулся с одной серьезной проблемой: как это обеспечить?

В течение последних нескольких дней я прекратил кодирование, и я постоянно занимался поиском в Интернете, StackOverflow и информационной безопасности, как это сделать. Я обнаружил, что способ, которым Amazon обеспечивает их API, будет лучшим решением для меня. Способ, которым Amazon обеспечивает его обслуживание, объясняется здесь. Я немного изменил его для моего обслуживания:

  • Пользователь регистрирует и получает закрытый ключ API + общедоступный ключ (идентификатор)
  • Пользователь вводит учетные данные и указывает "войти". Приложение создает хэш из переменных + закрытый ключ. Приложение отправляет переменные + метку времени + хэш + открытый ключ в API
  • API просматривает открытый ключ в базе данных, находит закрытый ключ, принадлежащий этому открытому ключу (если открытый ключ действителен). Затем API создает хеш так же, как и приложение. Если хеши одинаковы, выполняется запрос (вход в этот случай).

Этот способ обеспечения сервиса имеет смысл для меня, и я могу кодировать большую часть его. но у меня есть большая проблема, и я не могу найти для этого никакого решения:

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

Кто-нибудь знает, как решить эту проблему? любая помощь будет высоко оценена!

Ответ 1

Я думаю, что вы усложнили свою схему аутентификации. Я бы предложил использовать широко используемый протокол, например oauth2, для защиты вашего API - http://oauth.net/2/.
Существует множество клиентских библиотек и множество серверных плагинов, которые поддерживают и реализуют его, а также легко интегрируются в ваше приложение.

Ответ 2

Вот как я решил ту же проблему и почему я думаю, что ваша фактическая проблема отличается от той, которую вы думаете:

То, как Amazon делает это, имеет смысл, безопасен и проще реализовать, чем oAuth, поэтому я не уверен, почему все предлагают его использовать. Я использую метод Amazon, который выглядит следующим образом:

  • Пользователь регистрирует использование API. Мы обязательно создадим открытый ключ, секретный ключ и сохраним контактную электронную почту, роль (наши роли - "admin" и "пользователь" ), а затем установите для пользователя API status значение active. Это позволяет нам управлять разрешениями на основе ролей на сервере (ограничение скорости, контроль доступа и т.д.) И деактивировать учетную запись в любое время
  • Мы отправим клиентский идентификатор и секретный ключ клиенту. Там просто нет способа обойти это, чтобы вы сделали его максимально безопасным:
    • Только отправка токена один раз. Если пользователь забывает свой токен, ему необходимо зарегистрировать новый клиент API
    • Убедитесь, что выполнены все запросы по HTTPS, никаких исключений - это делает так, чтобы любой принт-флип-шифрование был зашифрован, а у злоумышленника только один выстрел для перехвата
    • Зашифровать токен в базе данных. Не хеш это, потому что он должен быть обратимым. Если вы надежно сохраняете свой ключ шифрования и генерируете новый случайный IV (вектор инициализации) при шифровании с помощью AES-256, тогда злоумышленник не сможет получить секретные ключи клиента (теоретически, если вы правильно закрепите этот ключ, но даже если не покупает вам некоторое время для дезактивации скомпрометированных клиентских токенов). Вы отправляете текстовый токен клиенту, когда он сгенерирован, но шифрует его до того, как он попадет в базу данных.
  • Когда клиент делает запрос, они отправляют заголовок и подписанный запрос. На вашем сервере вы найдете зашифрованный токен, связанный с идентификатором клиента, расшифруйте его, затем вычислите подпись и сравните ее с тем, что было отправлено. Если ваша вычисленная подпись и их соответствие совпадают, вы можете продолжить запрос.

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

Проблема, которую вам не хватает, заключается в том, как защитить этот токен от самого устройства. Это еще одна проблема, для которой я не видел никаких решений.

Единственными жизнеспособными вариантами для обоих этих случаев являются:

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

Одна мера, которую мы придумали для фиксации токена на устройстве, - это периодически поворачивать токены. Так, например, у вас есть токен, который хранится на устройстве для каждого пользователя или жестко закодирован в приложении. Каждый так часто вам нужен новый токен для устройства. Если у вас жестко закодированный токен, то вы обновляете приложение с помощью нового жестко закодированного токена, и когда пользователь обновляется через свой магазин приложений, он автоматически получит новый токен. Затем вы отменяете все токены, которым исполнилось X дней, и требуйте отставших разработчиков обновить приложение. Другой вариант, если каждому клиенту предоставляется уникальный токен при регистрации/регистрации, также истекает токен, а затем автоматически выводит их в следующий раз, когда они используют приложение. При входе в систему вы создаете и отправляете им новый токен, действительный для X дней.

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

Ответ 3

Как сказал Ротер Хермон, я бы также реализовал Oauth2.

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

Глупый абстрагированный пример:

Сервер имеет ключ частных клиентов ( "Z" ) Клиент имеет свой закрытый ключ ( "Z" )

Они оба знают свой открытый ключ ( "Y" )

Клиент хэширует запрос к ресурсу ( "A" ) и свой закрытый и открытый ключ для подписи запроса с помощью такой функции signMyRequest(request,publicKey,privateKey)

В этом примере будет signMyRequest("A","Y","Z")

Открытый ключ будет соответствовать роли "имени пользователя", а закрытый ключ будет соответствовать роли "пароля". Разница заключается в том, что вы не передаете его серверу, AWS просто делает расчет по закрытому ключу. Подпишитесь на подписку AWS V4 для получения дополнительной информации: http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html

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

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