Мобильное приложение Starbucks — один из самых известных кейсов в ecommerce. Автор материала — программист опытным путем доказывающий, почему стоит открыть API этого приложения.
Стоит отдать должное приложению Starbucks — оно просто отличное. Я использую его (как минимум) раз в день. В нем есть все, что мне нужно от отличного мобильного сервиса — кофе, плейлисты хитов 80-х в Spotify и возможность избежать живого общения с другими людьми. Я явно не одинок в своих предпочтениях, так как 20% операций Starbucks в США сейчас производится через мобильные телефоны.
Помимо интеграции Slack и кофейных кнопок существует множество других интеграций, которые можно было бы реализовать, если бы компания открыла свой API для сторонних разработчиков. Она явно движется в этом направлении, поскольку у нее есть и аккаунт в Twitter, и (защищенный паролем) веб-сайт для разработчиков.
Однако я не мог ждать и поэтому решил взять дело в свои руки.
Приложение Starbucks оказалось крепким орешком. Несмотря на URL-адрес «openapi.starbucks.com», пришлось пробираться через серьезные дебри, прежде чем начать анализировать вызовы, совершаемые приложением. Как и для любого другого приложения, обрабатывающего платежи, Starbucks предпринял многочисленные меры безопасности для защиты API, используемых своим приложением, от несанкционированного использования. Вот некоторые из них:
Для начала мне нужен был способ наблюдать за запросами и ответами, которыми обменивались приложение Starbucks и его сервера. Обычно я просто настраивал свой iPhone на Charles (или mitmproxy), и этого было достаточно.
Но не в этот раз! Поскольку приложение использует certificate pinning, я не смог перехватить его запросы, как обычно. Вместо этого мне пришлось откопать свой старый телефон на Android, получить root-права, установить фреймворк под названием Xposed и, наконец, установить расширение, которое внедряется в запущенные приложения и отключает SSL pinning.
Муахаха
После его запуска я смог начать просмотр запросов с использованием прокси-сервера Charles. Однако это оказалось скорее ложной надеждой, так как не все запросы можно было легко воспроизвести. Тем не менее, я смог запросить основную информацию, например, о ближайших магазинах, меню и балансах карт.
Результат запроса о ближайшем магазине. Теперь вы знаете, где я работаю. Упс.
А вот и нет.
Как выяснилось, токены доступа Starbucks действительны всего один час, поэтому нельзя просто взять и пользоваться тем токеном, который использует ваш телефон. Это создает определенные трудности…
Конечная точка OAuth, используемая приложением, перед выдачей токена проверяет три параметра:
Я начал пытаться сформировать некоторые из них самостоятельно. Я смог получить ключ шифрования, используемый для создания deviceFingerprint, используя джейлбрейкнутый iPhone для расшифровки фреймворков внутри приложения Starbucks. Изучив фреймворк в Hopper в течение некоторого времени, я в конечном итоге смог отследить вызов к функции Apple CCCrypt.
www.youtube.com/watch?v=o8ZnCT14nRc
Затем я прилинковал фреймворк SBXData (фреймворк, который я ранее расшифровал на джейлбрейкнутом телефоне) в наскоро созданное приложение и воспользовался Fishhook для переназначения этой функции собственной реализации. Это позволило мне выгрузить ключ и связанные с ним параметры в консоль:
Аналогичным образом удалось выяснить, как генерировать заголовок «X-Cbt». Для краткости изложения, я оставлю эту задачу вам :)
После того, как я смог подписать и снять отпечатки со своих запросов на вход, я объединил все в небольшой модуль Node.js, который позволяет использовать некоторые основные функции API Starbucks. Хорошие новости: он (в основном) размещен здесь на GitHub!
Вуаля! Программируемый кофе.
Мотивация
Стоит отдать должное приложению Starbucks — оно просто отличное. Я использую его (как минимум) раз в день. В нем есть все, что мне нужно от отличного мобильного сервиса — кофе, плейлисты хитов 80-х в Spotify и возможность избежать живого общения с другими людьми. Я явно не одинок в своих предпочтениях, так как 20% операций Starbucks в США сейчас производится через мобильные телефоны.
Помимо интеграции Slack и кофейных кнопок существует множество других интеграций, которые можно было бы реализовать, если бы компания открыла свой API для сторонних разработчиков. Она явно движется в этом направлении, поскольку у нее есть и аккаунт в Twitter, и (защищенный паролем) веб-сайт для разработчиков.
Однако я не мог ждать и поэтому решил взять дело в свои руки.
Было нелегко
Приложение Starbucks оказалось крепким орешком. Несмотря на URL-адрес «openapi.starbucks.com», пришлось пробираться через серьезные дебри, прежде чем начать анализировать вызовы, совершаемые приложением. Как и для любого другого приложения, обрабатывающего платежи, Starbucks предпринял многочисленные меры безопасности для защиты API, используемых своим приложением, от несанкционированного использования. Вот некоторые из них:
- SSL certificate pinning
- Создание цифрового отпечатка атрибутов вашего мобильного телефона, чтобы понять, используете ли вы смартфон
- Шифрование этого отпечатка с использованием AES, 256-битным ключом и псевдослучайным вектором инициализации
- Подписание запросов с меткой текущего времени
Наблюдение за запросами сети
Для начала мне нужен был способ наблюдать за запросами и ответами, которыми обменивались приложение Starbucks и его сервера. Обычно я просто настраивал свой iPhone на Charles (или mitmproxy), и этого было достаточно.
Но не в этот раз! Поскольку приложение использует certificate pinning, я не смог перехватить его запросы, как обычно. Вместо этого мне пришлось откопать свой старый телефон на Android, получить root-права, установить фреймворк под названием Xposed и, наконец, установить расширение, которое внедряется в запущенные приложения и отключает SSL pinning.
Муахаха
После его запуска я смог начать просмотр запросов с использованием прокси-сервера Charles. Однако это оказалось скорее ложной надеждой, так как не все запросы можно было легко воспроизвести. Тем не менее, я смог запросить основную информацию, например, о ближайших магазинах, меню и балансах карт.
Результат запроса о ближайшем магазине. Теперь вы знаете, где я работаю. Упс.
«Это легко», — думал я, — «Я просто размещу заказ, подключившись к прокси-серверу, и потом воспроизведу запросы!»
А вот и нет.
Как выяснилось, токены доступа Starbucks действительны всего один час, поэтому нельзя просто взять и пользоваться тем токеном, который использует ваш телефон. Это создает определенные трудности…
Вход в систему
Конечная точка OAuth, используемая приложением, перед выдачей токена проверяет три параметра:
- Параметр строки запроса sig. Исследователь проблем безопасности Райан Пикрен выяснил, что это клиентский ключ, клиентский секретный ключ и текущая временная метка UNIX, конкатенированные вместе и прогнанные через функцию MD5-хэширования.
- Параметр формы «deviceFingerprint». Это список различных атрибутов устройства в кодировке base64 и зашифрованный AES-256. Он также регулярно изменяется, поскольку текущее время и аптайм устройства включены в отпечаток.
- HTTP-заголовок «X-Cbt». Еще одна строка секретного ключа в кодировке base64.
Я начал пытаться сформировать некоторые из них самостоятельно. Я смог получить ключ шифрования, используемый для создания deviceFingerprint, используя джейлбрейкнутый iPhone для расшифровки фреймворков внутри приложения Starbucks. Изучив фреймворк в Hopper в течение некоторого времени, я в конечном итоге смог отследить вызов к функции Apple CCCrypt.
www.youtube.com/watch?v=o8ZnCT14nRc
Затем я прилинковал фреймворк SBXData (фреймворк, который я ранее расшифровал на джейлбрейкнутом телефоне) в наскоро созданное приложение и воспользовался Fishhook для переназначения этой функции собственной реализации. Это позволило мне выгрузить ключ и связанные с ним параметры в консоль:
Аналогичным образом удалось выяснить, как генерировать заголовок «X-Cbt». Для краткости изложения, я оставлю эту задачу вам :)
Заключение
После того, как я смог подписать и снять отпечатки со своих запросов на вход, я объединил все в небольшой модуль Node.js, который позволяет использовать некоторые основные функции API Starbucks. Хорошие новости: он (в основном) размещен здесь на GitHub!
Вуаля! Программируемый кофе.