Реверс API Сбербанка
Зачем
У меня есть pet-project, приложение для учета финансов. На мой взгляд одной из ключевых проблем подобных приложений является ручной ввод баланса. У банков, в частности сбера, есть информация о транзакциях которые я совершаю и даже есть неплохая аналитика.
Но
- Банков несколько и они ничего не знают друг про друга. В итоге
- Нет единой аналитики
- Перевод денег из одного банка в другой будет считаться как списание с одной стороны и зачисление с другой. Эта особенность портит аналитику.
- Возможность работать с данными позволяет строить любую аналитику и прогнозы в отличие от ui банка
Приложения, в отличие от сайтов, запрашивают данные с сервера и только в своих кишках делают из него UI. В то время как сайты зачастую отчасти рендерятся на сервере. В приложения обычно приходят уже удобные json/xml.
Как
К сожалению, банки не выкладывают документацию на API в открытый доступ. Но его довольно легко получить из android приложения.
Краткая инструкция
- Качаем charles, apktool, «штука для подписи приложений»
- Подготавливаем приложение к MITM
- С помощью apktool анбоксим приложение
apktool d -f -r Sberbank.apk
- Выгружаем из charles корневой сертификат
Help > SSL Proxying > Save Charles Root Certificate
- Заменяем доверенный сертификат сбербанка на сертификат charles
cp
Sberbank/res/raw/thawte_rsa_ca_2018_thawte_ssl_wildcard.cer - Теперь приложение будет доверять charles вместо сбера.
- С помощью apktool анбоксим приложение
- Собираем приложение обратно
apktool b Sberbank -o ${apkName}
- И подписываем его
java -jar sign.jar ${apkName}
- Подписанное приложение устанавливается вместо настоящего на телефон
- Конфигурируем телефон на проксирование трафика через Charles
(в настройках wifi выбирается Proxy. IP - машины с charles, PORT-8888)
- Запускаем приложение и снифим трафик.
Итог
Получилась библиотека для kotlin.jvm. Под капотом используется okhttp для запросов
и jackson для парсинга xml. Есть возможность как получать сырые данные из XML, так и смапленные в объектную, автосгенеренную модель
Пример использования
println("login:")
// mguid Является переиспользуемым и получается один раз при регистрации девайса
val mguid = SberbankRegistration().register(readLine()!!) {
println("smsPassword:")
readLine()!!
}
//Логин нужно выполнять 1 раз на сессию
val sberbank = SberbankLogining().login(mguid)
val products = sberbank.productList()
val result = ArrayList()
for (card in products.cards!!.list!!) {
val elements = sberbank.paymentsList(
card = card,
from = LocalDate.now().minusYears(5),
to = LocalDate.now(),
paginationSize = Short.MAX_VALUE.toInt(),
paginationOffset = 0
).operations
if(elements!=null){
result.addAll(elements)
}
}
print(result)
Буду рад помощи в развитии проекта, например в публикации API в maven central.