Как защитить API от неавторизованных запросов на создание заказа в мобильном приложении?
Что проверяют
Понимаете ли вы, что защита живёт на сервере, а клиент на телефоне пользователя по определению недоверенный. iOS-разработчику важно показать, что делает приложение (хранит токены, подтверждает подлинность устройства), и не выдавать это за защиту API. Следом спрашивают, что помешает повторить запрос из консоли с вашим токеном.
Как отвечать
Разделите ответ на клиент и сервер. На клиенте:
- авторизация пользователя: OAuth 2.0 с PKCE, для внешнего входа
ASWebAuthenticationSession. Короткий access-токен и refresh-токен, обновление централизованно в сетевом слое, например вactor, чтобы параллельные запросы не обновляли токен наперегонки; - хранение: токены в Keychain с подходящим уровнем доступности вроде
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, а не вUserDefaults; - подлинность приложения: App Attest из фреймворка
DeviceCheck(DCAppAttestService) подписывает запросы ключом из Secure Enclave, и сервер проверяет, что заказ создаёт настоящая копия приложения; - транспорт: App Transport Security по умолчанию требует HTTPS. Pinning сертификатов возможен, но это защита от перехвата, а не от поддельного клиента.
На сервере: проверка токена на каждом запросе, user_id берётся из токена, а не из тела, цены и скидки пересчитываются заново, ключ идемпотентности в заголовке защищает от двойного заказа при повторе, rate limiting по пользователю и устройству, логирование отказов.
Где спотыкаются
Прячут API-ключ в Info.plist или в коде и считают это защитой. Строки из бинарника достаются за минуты, секрет в клиенте секретом не является.
Доверяют данным из запроса: сумме заказа, user_id, статусу оплаты. Любое поле меняется через перехватывающий прокси вроде mitmproxy.
Хранят токен в UserDefaults. Это обычный plist в контейнере приложения: он попадает в бэкапы и читается на взломанном устройстве без усилий.