В статье в основном говорится об авторизации и верификации вызовов мобильного API.Оригинальная ссылка:The Ultimate Guide to Mobile API Security
Использование мобильного API — частая тема на Stack Overflow и на канале поддержки Stormpath. Это решаемая проблема, но для правильной реализации требуется много необходимых знаний и адекватного понимания.
В этой статье вы найдете все, что вам нужно знать о безопасном вызове Restful API на мобильных устройствах, независимо от того, создаете ли вы мобильное приложение, которому требуется доступ к Restful API, или вы пишете Restful API и планируете взаимодействовать с разработчиками мобильных приложений.
Моя цель — не только объяснить, как гарантировать, что мобильные разработчики могут безопасно вызывать ваш Restful API, но и объяснить весь процесс обмена учетными данными от начала до конца, как восстановиться после нарушений безопасности и многое другое.
Проблемы безопасности мобильного API
Прежде чем мы углубимся в то, как гарантировать, что мобильные разработчики могут безопасно вызывать Restful API, давайте обсудим, чем мобильная аутентификация отличается от традиционной аутентификации API.
Самая простая форма аутентификации API обычно известна какHTTP Basic Authentication.
Для разработчиков сервиса API и тех, кто его использует, принцип его работы очень прост:
- Разработчик получает API-ключ (обычно ID и Secret). Этот ключ API обычно выглядит так:
3bb743bbd45d4eb8ae31e16b9f83c9ba:ffb7d6369eb84580ad2e52ca3fc06c9d
. - Разработчик несет ответственность за хранение ключа API в безопасном месте, где его никто не сможет получить.
- Когда разработчик инициирует запрос API, ключ API должен быть помещен в
HTTP Authorization header
, с ключевыми словамиBasic
(То есть и имя пользователя, и пароль зашифрованы с помощью base64). Ниже показано, как разработчик может указать ключ API для аутентификации при вызове API с помощью инструмента командной строки.cURL
.
$ curl --user 3bb743bbd45d4eb8ae31e16b9f83c9ba:ffb7d6369eb84580ad2e52ca3fc06c9d https://api.example.com/v1/test
скопировать код
cURL
Инструмент может зашифровать полученный сертификат API с помощью base64, а затем создатьHTTP Authorization hearder
,Следующее:Basic M2JiNzQzYmJkNDVkNGViOGFlMzFlMTZiOWY4M2M5YmE6ZmZiN2Q2MzY5ZWI4NDU4MGFkMmU1MmNhM2ZjMDZjOWQ=.
. И сервер API запустится сHTTP Authorization hearder
Получите строку в , а затем расшифруйте ее с помощью base64, чтобы получить идентификатор и секрет, а затем обработайте соответствующий запрос API после прохождения проверки.
Базовая HTTP-аутентификация проста, но очень полезна. Ключ API, предоставленный разработчиком при вызове API, может быть хорошо аутентифицирован сервером API.
Однако, поскольку мобильные приложения не могут безопасно хранить ключи API, базовая проверка подлинности HTTP не является хорошим выбором. В то же время HTTP Basic Authentication требует использования исходных ключей API для каждого запроса, в результате чего ключи используются в течение длительного времени, что не является безопасным.
Поэтому в большинстве случаев этот метод аутентификации нецелесообразен, поскольку ключи API нельзя надежно встроить в мобильные приложения, распространяемые среди множества пользователей.
Например, вы можете внедрить ключи API в создаваемое вами мобильное приложение, но опытный пользователь может перепроектировать ваше приложение, получить ключи и злоупотребить вашей службой API.
Вот почему базовая HTTP-аутентификация — не лучший вариант в ненадежных средах, таких как веб-браузеры и мобильные приложения.
Уведомление:Как и все другие протоколы аутентификации, базовая аутентификация HTTP должна использоваться через SSL.
Представляем OAuth 2.0 для мобильной безопасности
Вы, наверное, уже слышали об OAuth и обсуждали, что это такое, и что он недостаточно хорош. Итак, давайте проясним: OAuth2 — отличный протокол для защиты служб API на ненадежных устройствах. Он аутентифицирует мобильных пользователей с помощью метода аутентификации, который мы называем токеном.
Ниже мы видим, как работает аутентификация токена OAuth2 с точки зрения пользователя.
- Пользователь открывает мобильное приложение и вводит учетную запись и пароль.
- Мобильное приложение отправляет запрос POST с именем пользователя и паролем на сервер API, сервер проверяет его и возвращает код в случае успеха.
- Мобильное приложение отправляет запрос на сервер аутентификации через код.После успешной аутентификации для пользователя генерируется токен доступа, срок действия которого истекает через определенный период времени.
- Храните токен доступа локально на мобильном устройстве, как ключ API, который обеспечивает доступ к службам API.
- По истечении срока действия токена доступа он больше не будет работать, и пользователю необходимо снова ввести имя пользователя и пароль, а также повторить шаги 1.
Причина, по которой OAuth2 отлично подходит для защиты API, заключается в том, что нам не нужно долго хранить ключи API в небезопасной среде, а вместо этого создавать временный токен доступа. Это защищает от некоторых потенциальных атак.
Теперь, когда ваша служба API генерирует токен Oauth2, необходимый вашему мобильному приложению, вам, конечно же, нужно сохранить его в своем мобильном приложении.
Но где? !
Место хранения токена зависит от платформы разработки, на которой вы работаете. Если вы разрабатываете приложение для Android, вы будете хранить токены доступа в SharedPreferences, если вы являетесь разработчиком IOS, вы будете хранить токены доступа в Keychain.
Если у вас все еще есть сомнения, следующие две публикации Stack Overflow могут быть очень полезными, в них подробно описывается, как хранить токены доступа в мобильных приложениях.
Теперь вы должны немного узнать об OAuth2, почему вам следует его использовать и как он работает.
Access Tokens
Давайте обсудим токены доступа. Кто они такие? Это строка случайно сгенерированных чисел? уид? или что-то другое?
Это хороший вопрос.
Вот более короткий ответ: токен доступа технически представляет собой любую строку, которую вы хотите:
- случайное число
- случайная строка
- UUID
- Более
Более подробное объяснение:
- генерируется для клиента.
- Убедитесь, что владельцем токена являетесь вы (используя надежную подпись)
- Срок годности есть.
С приведенным выше объяснением вы, возможно, захотите соблюдать определенные нормы. Чтобы не заниматься этим самостоятельно, вы можете использовать JWT (Json Web Token) напрямую. Это относительно новая спецификация, позволяющая генерировать токены доступа. Эта спецификация (RFC7519) удовлетворяет следующим требованиям: - можно сгенерировать для клиента
- Может быть проверено создателем
- Автоматически истекает через определенное время
- Может содержать переменную информацию JSON
- Нет необходимости запрашивать службу API, что позволяет пользователям аутентифицировать учетные данные API локально, тем самым уменьшая количество вызовов API.
JWT выглядят как случайно сгенерированные строки, и вы можете хранить их как строки при их использовании. Это делает очень удобным использование JWT вместо традиционных токенов доступа, в конце концов, они в основном одинаковы, а у JWT больше преимуществ.
JWT всегда аутентифицируются криптографически. Принцип их работы следующий:
- Сохраните защищенную случайную строку где-нибудь на сервере API. Обычно это относительно длинная случайная строка (около 40 символов).
- Когда вы создаете новый JWT, вам нужно передать эту случайную строку в библиотеку JWT, чтобы подписать токен вместе с некоторыми данными, которые вы хотите сохранить, такими как идентификатор пользователя, адрес электронной почты и т. д.
- Токен будет сгенерирован и будет выглядеть так:
header.claims.signature
--header, утверждения и подпись представляют собой строки, зашифрованные с помощью base64. - Сообщите сгенерированный токен пользователю, обычно пользователю API, например мобильного приложения.
Теперь из мобильного клиента вы можете увидеть все, что хранится в JWT. поэтому, если у меня есть JWT, я могу легко увидеть содержащиеся в нем данные JSON, обычно так:
{
"user_id": "e3457285-b604-4990-b902-960bcadb0693",
"scope": "can-read can-write"
}
скопировать код
Конечно, это на 100% вымышленный пример, но из этого можно сказать, что если вы получите копию этого JWT, вы также сможете увидеть хранящуюся в нем информацию JSON.
Стандарт JWT поддерживает автоматическую маркировку срока действия, поэтому вы также можете убедиться, что JWT действителен. Независимо от того, какой язык вы используете, пока вы используете библиотеку JWT, вы можете проверить действительность JWT до истечения срока ее действия!
Это означает, что если вы используете JWT для доступа к службе API, вам нужно только проверить JWT, чтобы узнать, будет ли работать ваш вызов API, вызов API не требуется.
Теперь, когда у вас есть действительный JWT, вы также можете делать с ним интересные вещи на стороне сервера.
Предположим, вы опубликовали JWT в своем мобильном приложении со следующими данными:
{
"user_id": "e3457285-b604-4990-b902-960bcadb0693",
"scope": "can-read can-write"
}
скопировать код
Предположим, в мобильном приложении есть вредоносный код, который может изменить ваш JWT, например:
{
"user_id": "e3457285-b604-4990-b902-960bcadb0693",
"scope": "can-read can-write can-delete"
}
скопировать код
Что произойдет, если этот модифицированный токен будет отправлен на наш сервер API? Это будет работать? Примет ли наш сервер этот модифицированный JWT?
Уведомление! !
Когда ваш API-сервис получает JWT и проверяет его, он делает несколько вещей:
- Убедитесь, что токен не был подделан, проверив токен с помощью случайно сгенерированной строки, известной только серверу. Если JWT полностью изменен, эта проверка завершится неудачно, и вы узнаете, что кто-то пытается сделать что-то нехорошее.
- В то же время сервер проверит срок действия JWT, чтобы убедиться в его легитимности. Поэтому, если клиент делает запрос с токеном с истекшим сроком действия, вы можете немедленно отклонить его.
Это хорошая функция, потому что она упрощает обработку проверки/истечения срока действия/безопасности.
Единственное, что вам нужно помнить при использовании JWT, это:Не храните конфиденциальную информацию в JWT.
Помня о вышеупомянутых правилах, вы не ошибетесь при использовании JWT.
Обычно вы будете хранить две части информации в JWT:
- Какой-то уникальный идентификатор для учетной записи пользователя. Таким образом, когда вы получаете этот JWT для аутентификации, вы можете найти этого пользователя в базе данных пользователей.
- Права пользователя. Конечно, это может не понадобиться при создании простого API, к которому могут получить доступ все пользователи. Но благодаря этому пользователям не нужно смотреть документацию API, чтобы узнать, что они могут и чего не могут делать, им просто нужно взглянуть на свой собственный JWT.
Это все, что нужно сказать о JWT.
Как работают JWT
В этом разделе мы подробно обсудим весь процесс, от начала до конца, а также все низкоуровневые технические детали, необходимые для создания безопасных API-сервисов, которые можно безопасно использовать с мобильных устройств.
Конкретный рабочий процесс показан на следующем рисунке:
1. User Opens App
Пользователь открывает приложение и переходит к следующему шагу.
2. App Asks for Credentials
Поскольку мы собираемся использовать схему типа предоставления пароля OAuth2 для аутентификации пользователей в нашей службе API, ваше приложение должно запрашивать у пользователя имя пользователя, адрес электронной почты и пароль.
Сейчас это требуют практически все мобильные приложения, поэтому пользователи привыкли вводить эту информацию.
3. User Enters their Credentials
Пользователь вводит свои учетные данные, следующий шаг.
4. App Sends POST Requests to API Service
Здесь начинается первоначальный поток OAuth2. Что вам нужно сделать, так это отправить простой HTTP-запрос POST из вашего мобильного приложения в службу API.
это использованиеcURL
Пример отправки POST-запроса:
$ curl --form 'grant_type=password&username=USERNAMEOREMAIL&password=PASSWORD' https://api.example.com/v1/oauth
скопировать код
Здесь мы отправляем имя пользователя или адрес электронной почты и пароль в нашу службу API, используя тип предоставления пароля OAuth2: (Существует несколько типов предоставления, но мы поговорим об этом, поскольку это единственный подходящий , при обсуждении создания собственного мобильного API).
5. API Server Authenticates the User
Далее происходит следующее: служба API извлекает входящие данные имени пользователя или электронной почты и пароля и проверяет учетные данные пользователя.
Этот шаг будет отличаться для разных платформ разработки, но общие шаги таковы:
- Запросите информацию об учетной записи пользователя с помощью имени пользователя и пароля.
- Сравните зашифрованную информацию о пароле.
- Если проверка прошла успешно, перейдите к следующему шагу, в противном случае верните сообщение об ошибке и проверка недействительна.
6. API Server Generates a JWT that the App Stores
Теперь, когда сервер аутентифицировал запросы OAuth2 приложения, необходимо сгенерировать токен доступа для приложения. Для этого сервер будет использовать библиотеку JWT для создания полезного токена доступа, который затем возвращается приложению.
- Создайте токен доступа в соответствии с правилами JWT.
- Верните его как JSON, как показано ниже.
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJEUExSSTVUTEVNMjFTQzNER0xHUjBJOFpYIiwiaXNzIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hcHBsaWNhdGlvbnMvNWpvQVVKdFZONHNkT3dUVVJEc0VDNSIsImlhdCI6MTQwNjY1OTkxMCwiZXhwIjoxNDA2NjYzNTEwLCJzY29wZSI6IiJ9.ypDMDMMCRCtDhWPMMc9l_Q-O-rj5LATalHYa3droYkY",
"token_type": "bearer",
"expires_in": 3600
}
скопировать код
Как вы можете видеть выше, наш ответ JSON содержит 3 поля. Первое поле, access_token, — это фактический токен доступа OAuth2, который с этого момента будет использовать мобильное приложение для выполнения аутентифицированных запросов API.
второе полеtoken_type
Просто сообщите мобильному приложению, какой тип токена доступа мы предоставляем — в данном случае мы предоставляем токен носителя OAuth2. Я расскажу об этом позже.
Наконец, третье предоставленное полеexpires_in
поле. По сути, это количество секунд, в течение которых действителен предоставленный токен доступа.
В приведенном выше примере мы говорим, что даем мобильному приложению токен доступа, который можно использовать для доступа к нашему частному API на срок до 1 часа — не более. Через 1 час (3600 секунд) срок действия этого токена доступа истечет, и любые будущие вызовы API, которые мы будем делать с этим токеном доступа, не будут выполняться.
На стороне мобильного приложения вы получите этот ответ JSON, проанализируете маркер доступа, предоставленный сервером API, и сохраните его локально в безопасном месте. На Android это означаетSharedPreferences
, на iOS это означаетKeychain
.
Теперь, когда токен доступа надежно хранится на мобильном устройстве, его можно использовать для выполнения всех последующих запросов API к серверу API.
7. App Makes Authenticated Requests to API Server
Все, что вам нужно сделать сейчас, это сделать безопасный запрос API к вашей службе API из вашего мобильного приложения.
На последнем этапе мобильное приложение получает токен доступа OAuth2, который затем сохраняется локально на устройстве.
Чтобы успешно выполнять запросы API с использованием этого токена, вам необходимо создать заголовок авторизации HTTP, который использует этот токен для идентификации вашего пользователя.
Для этого все, что вам нужно сделать, это объединить свой токен доступа сBearer
вставляются вместе в заголовок авторизации HTTP. Вот пример использования cURL:
$ curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJEUExSSTVUTEVNMjFTQzNER0xHUjBJOFpYIiwiaXNzIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hcHBsaWNhdGlvbnMvNWpvQVVKdFZONHNkT3dUVVJEc0VDNSIsImlhdCI6MTQwNjY1OTkxMCwiZXhwIjoxNDA2NjYzNTEwLCJzY29wZSI6IiJ9.ypDMDMMCRCtDhWPMMc9l_Q-O-rj5LATalHYa3droYkY" https://api.example.com/v1/test
скопировать код
Наконец, заголовок авторизации выглядит так:
Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJEUExSSTVUTEVNMjFTQzNER0xHUjBJOFpYIiwiaXNzIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hcHBsaWNhdGlvbnMvNWpvQVVKdFZONHNkT3dUVVJEc0VDNSIsImlhdCI6MTQwNjY1OTkxMCwiZXhwIjoxNDA2NjYzNTEwLCJzY29wZSI6IiJ9.ypDMDMMCRCtDhWPMMc9l_Q-O-rj5LATalHYa3droYkY
скопировать код
Когда ваш API-сервер получит этот HTTP-запрос, он сделает следующее:
- Проверьте значение заголовка авторизации HTTP, будь то из
Bearer
Начинать. - Получите значение следующей строки в качестве токена.
- Убедитесь, что JWT действителен. Если он действителен, расшифруйте base64, чтобы получить идентификатор пользователя, разрешения и другую информацию, а затем выполните оставшиеся вызовы интерфейса API.
(Заканчивать)
Суммировать
В этой статье описываются текущие методы проверки подлинности для вызовов API мобильных приложений. Когда речь идет об общем методе аутентификации HTTP, аутентификации OAuth2.0 и JWT, их принципы четко описаны, поэтому они переведены для всеобщего обозрения.
Единственное, что, я думаю, может ввести читателей в заблуждение, — это описание связи между токенами доступа и JWT в OAuth 2.0. Итак, чтобы разобраться следующим образом:
- OAuth2.0 — это инфраструктура авторизации, а JWT — протокол аутентификации.
- В OAuth2.0 токен доступа на самом деле представляет собой случайную строку, а токены доступа, сгенерированные разными языками разработки и разными фреймворками безопасности, различаются. Конечно, вы также можете использовать JWT в качестве токена доступа, как указано в статье.
- Когда OAuth2.0 запрашивает сервер авторизации через код, возвращается следующая информация. Возвращаемые данные содержат
expires_in
, который представляет время истечения срока действия. Токен, сгенерированный JWT, разбит на три секции, и после расшифровки через base64 время истечения можно получить без возврата отдельного поля.
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}
скопировать код
- Токен доступа в OAuth2.0 генерируется полностью случайным образом и сам по себе не имеет смысла.Для выполнения проверки сгенерированный токен доступа и время истечения необходимо хранить в базе данных. Сам JWT может нести некоторую неконфиденциальную информацию и время истечения срока действия, и его можно расшифровать с помощью base64 без сохранения в базе данных. По этой причине, как упоминалось выше, JWT введен в OAuth2.0 в качестве токена доступа, поэтому серверу не нужно поддерживать хранилище токенов, а серверу ресурсов не нужно требовать проверки токенов.