Разбираемся, что записывает, а что не записывает приложение Burger King

в 15:42, , рубрики: Andoid, Burger King, аналитика, Аналитика мобильных приложений, информационная безопасность

Разбираемся, что записывает, а что не записывает приложение Burger King - 1
Это статья является ответом на статью пользователя fennikami о том как нехороший Burger King записывает видео с экрана смартфона. В оригинальной статье утверждается, что таким образом Burger King может получить доступ к информации о вводимых картах, тем самым скомпрометирован их. Я постараюсь разобраться все ли так на самом деле.

Моему анализу подверглось Android приложение версии 2.2.2 с датой обновления 9 июля 2018г. Результаты на других платформах и в других версиях приложения могут отличаться от приведенных в этой статье.

Инициализация Appsee

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

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

{
  "AutoDetectScreens": true,
  "AutoHideWebComponents": true,
  "ClientId": "5b47182e7b2f3f1429341f73",
  "ClientLogsUploadPolicy": 2,
  "ConfigHttpTimeoutInMilliseconds": 5000,
  "DetectActions": true,
  "DetectCrashes": true,
  "DetectGestures": true,
  "DetectMenus": true,
  "DetectPopups": true,
  "HideInput": true,
  "HideSensitiveViews": true,
  "MaxEventProperties": 5001,
  "MaxVideoLength": 0,
  "OfflineConfigurationPolicy": 1,
  "RecordMetadata": true,
  "RecordVideo": true,
  "SensitiveMaskingPerWindow": true,
  "SessionId": "5b4718ec470302299bdcc04d",
  "TrackedOfflineSessions": {},
  "UploadAppIcon": false,
  "UploadBenchmarks": false,
  "UploadTouchEvents": true,
  "UploadVideoOnCrash": true,
  "UseWebViewSnapshotFullscreen": false,
  "VideoBitrate": 56,
  "VideoFPS": 3,
  "VideoHeight": 320,
  "VideoWidth": 160
}

Можно заметить, что параметры HideInput, HideSensitiveViews имеют значение true, скрывая тем самым важную информацию в видео. Сразу возникает вопрос как определяется важность информации, для ответа обратимся к документации Appsee. Если коротко, то по умолчанию скрытию подвергаются все поля для ввода данных, дополнительно можно настроить скрытие для других полей или частей интерфейса.

Так же обратим внимание с каким качеством ведется запись видео, в моем случае это было видео с разрешением 320 на 160 пикселей, с частотой три кадра в секунду.

Реальные данные собираемые Appsee

Я решил проверить какие данные действительно отправляются на сервера Appsee, для этого я использовал Proxy из Burp Suite. Сначала система аналитики передает файл с действиями пользователя внутри приложения, там в том числе есть координаты нажатий пользователя, нажатия на клавиатуре не фиксируются.

Данные собираемые Appsee, пользовательские действия

{"InitialOrientation":1,"InitialAppFrame":[0,0,1080,1776],"Crashed":false,"Duration":143361,"PreSessionDuration":2360,"VideoRecorded":true,"CustomEvents":[{"n":"open_screen","t":9688,"p":{"authorized":"no","screen":"sms","source":"auth_screen1","device_id":"9c843736-8da0-4832-ac9f-de83f5fe889b"}},{"n":"popup_screen","t":38560,"p":{"screen":"PromoGridFragment","device_id":"9c843736-8da0-4832-ac9f-de83f5fe889b","user_name":"Илья","popup":"select_restaurant","authorized":"yes","user_id":258504}},{"n":"open_screen","t":38727,"p":{"screen":"coupons_public","device_id":"9c843736-8da0-4832-ac9f-de83f5fe889b","user_name":"Илья","authorized":"yes","user_id":258504}},{"n":"open_screen","t":44781,"p":{"screen":"my_orders","device_id":"9c843736-8da0-4832-ac9f-de83f5fe889b","user_name":"Илья","authorized":"yes","user_id":258504}},{"n":"open_screen","t":48549,"p":{"screen":"public_coupon_details","device_id":"9c843736-8da0-4832-ac9f-de83f5fe889b","user_name":"Илья","coupon_name":"2 Воппер Обеда","authorized":"yes","user_id":258504}},{"n":"open_screen","t":57971,"p":{"current_restaurant_name":"0632-МУР, Мурманск, просп Ленина 32, ТЦ Мурманск Молл 4 этаж","screen":"cart","device_id":"9c843736-8da0-4832-ac9f-de83f5fe889b","user_name":"Илья","user_id":258504,"authorized":"yes","current_paying_method":"none"}},{"n":"open_screen","t":60413,"p":{"screen":"bank_card","device_id":"9c843736-8da0-4832-ac9f-de83f5fe889b","user_name":"Илья","authorized":"yes","user_id":258504}}],"Screens":[{"n":"AuthActivity","a":true,"p":0,"s":0},{"n":"MainActivity","a":true,"p":0,"s":36819},{"n":"CouponDetailActivity","a":true,"p":0,"s":48749},{"n":"CouponSelectGoodsActivity","a":true,"p":0,"s":50593},{"n":"MainActivity","a":true,"p":0,"s":56982},{"n":"BasketActivity","a":true,"p":0,"s":58115},{"n":"AddCardActivity","a":true,"p":0,"s":60672}],"Popups":[],"Gestures":[{"t":0,"r":1,"s":2274,"e":2332,"g":[2],"b":{"x":0,"y":1011,"w":1080,"h":144}},{"t":0,"r":1,"s":43150,"e":43208,"g":[3],"b":{"x":624,"y":1437,"w":390,"h":102}},{"t":0,"r":1,"s":44717,"e":44720,"g":[4],"b":{"x":216,"y":1608,"w":216,"h":168}},{"t":0,"r":1,"s":50163,"e":50213,"g":[5],"b":{"x":0,"y":1584,"w":1080,"h":192}},{"t":0,"r":1,"s":54105,"e":54135,"g":[6],"b":{"x":540,"y":561,"w":540,"h":636}},{"t":0,"r":1,"s":55250,"e":55291,"g":[7],"b":{"x":540,"y":561,"w":540,"h":636}},{"t":0,"r":1,"s":56430,"e":56480,"g":[8],"b":{"x":0,"y":1584,"w":1080,"h":192}},{"t":4,"r":1,"s":59230,"e":59354,"g":[9]},{"t":0,"r":1,"s":60368,"e":60409,"g":[10],"b":{"x":0,"y":207,"w":1080,"h":1569}},{"t":0,"r":1,"s":61430,"e":61488,"g":[11],"b":{"x":0,"y":207,"w":1080,"h":1569}},{"t":0,"r":1,"s":62273,"e":62356,"g":[12],"b":{"x":0,"y":207,"w":1080,"h":1569}},{"t":0,"r":1,"s":62686,"e":62744,"g":[13],"b":{"x":0,"y":207,"w":1080,"h":1569}},{"t":0,"r":1,"s":70657,"e":70698,"g":[15],"b":{"x":0,"y":207,"w":1080,"h":954}},{"t":0,"r":1,"s":72611,"e":72660,"g":[16],"b":{"x":0,"y":207,"w":1080,"h":954}},{"t":0,"r":1,"s":73344,"e":73394,"g":[17],"b":{"x":120,"y":178,"w":98,"h":862}},{"t":0,"r":1,"s":73757,"e":73825,"g":[18],"b":{"x":0,"y":207,"w":1080,"h":1569}},{"t":0,"r":1,"s":74230,"e":74287,"g":[19],"b":{"x":0,"y":207,"w":1080,"h":1569}},{"t":0,"r":1,"s":74904,"e":74945,"g":[20],"b":{"x":334,"y":178,"w":148,"h":895}},{"t":0,"r":1,"s":75663,"e":75729,"g":[21],"b":{"x":0,"y":207,"w":1080,"h":1569}},{"t":0,"r":1,"s":76346,"e":76386,"g":[22],"b":{"x":334,"y":178,"w":148,"h":895}}],"Actions":[{"t":5,"s":380,"i":"1"},{"t":0,"s":2332,"i":"1","p":"Далее","id":"2131361874","iu":1,"b":{"x":0,"y":1011,"w":1080,"h":144}},{"t":8,"s":9736},{"t":7,"s":9745,"p":"false"},{"t":5,"s":32117,"i":"1"},{"t":8,"s":33907},{"t":5,"s":33910,"i":"1"},{"t":0,"s":44720,"i":"5","p":"Мои заказы","id":"2131361823","iu":1,"b":{"x":216,"y":1608,"w":216,"h":168}},{"t":4,"s":62744,"i":"1"},{"t":7,"s":62746,"p":"false"},{"t":5,"s":63425,"i":"1"},{"t":4,"s":70698,"i":"2"},{"t":5,"s":71401,"i":"1"},{"t":1,"s":73394,"i":"1","p":"0.7"},{"t":8,"s":73877},{"t":1,"s":74945,"i":"1","p":"0.6"},{"t":1,"s":76386,"i":"1","p":"0.5"}],"OrientationEvents":[],"AppFrameEvents":[],"ThirdPartyIds":[],"ANRs":[],"AppUserId":"258504","TouchEvents":[{"g":2,"e":0,"x":942,"y":1059,"t":2274,"k":1},{"g":2,"e":1,"x":942,"y":1059,"t":2332,"k":1},{"g":3,"e":0,"x":872,"y":1510,"t":43150},{"g":3,"e":1,"x":872,"y":1510,"t":43208},{"g":4,"e":0,"x":360,"y":1681,"t":44717},{"g":4,"e":1,"x":360,"y":1681,"t":44720},{"g":5,"e":0,"x":885,"y":1652,"t":50163},{"g":5,"e":1,"x":885,"y":1652,"t":50213},{"g":6,"e":0,"x":690,"y":656,"t":54105},{"g":6,"e":1,"x":690,"y":656,"t":54135},{"g":7,"e":0,"x":660,"y":685,"t":55250},{"g":7,"e":1,"x":660,"y":685,"t":55291},{"g":8,"e":0,"x":813,"y":1719,"t":56430},{"g":8,"e":1,"x":813,"y":1719,"t":56480},{"g":9,"e":0,"x":741,"y":1485,"t":59230},{"g":9,"e":2,"x":741,"y":1484,"t":59246},{"g":9,"e":1,"x":880,"y":893,"t":59354},{"g":10,"e":0,"x":905,"y":1467,"t":60368},{"g":10,"e":1,"x":905,"y":1467,"t":60409},{"g":11,"e":0,"x":644,"y":919,"t":61430},{"g":11,"e":1,"x":644,"y":919,"t":61488},{"g":12,"e":0,"x":633,"y":802,"t":62273},{"g":12,"e":1,"x":633,"y":802,"t":62356},{"g":13,"e":0,"x":636,"y":893,"t":62686},{"g":13,"e":1,"x":636,"y":893,"t":62744},{"g":14,"e":0,"x":717,"y":1059,"t":70151,"k":1},{"g":14,"e":2,"x":716,"y":1058,"t":70168,"k":1},{"g":14,"e":2,"x":760,"y":846,"t":70302,"k":1},{"g":14,"e":1,"x":775,"y":806,"t":70403,"k":1},{"g":15,"e":0,"x":901,"y":887,"t":70657,"k":1},{"g":15,"e":1,"x":901,"y":887,"t":70698,"k":1},{"g":16,"e":0,"x":194,"y":855,"t":72611,"k":1},{"g":16,"e":1,"x":194,"y":855,"t":72660,"k":1},{"g":17,"e":0,"x":153,"y":854,"t":73344,"k":1},{"g":17,"e":1,"x":153,"y":854,"t":73394,"k":1},{"g":18,"e":0,"x":465,"y":853,"t":73757,"k":1},{"g":18,"e":1,"x":465,"y":853,"t":73825,"k":1},{"g":19,"e":0,"x":474,"y":1006,"t":74230},{"g":19,"e":1,"x":474,"y":1006,"t":74287},{"g":20,"e":0,"x":419,"y":719,"t":74904},{"g":20,"e":1,"x":419,"y":719,"t":74945},{"g":21,"e":0,"x":499,"y":996,"t":75663},{"g":21,"e":1,"x":499,"y":996,"t":75729},{"g":22,"e":0,"x":415,"y":597,"t":76346},{"g":22,"e":1,"x":415,"y":597,"t":76386}]}

Видео передаваемое на сервера Appsee, как и следовало ожидать большинство данных скрыты

Смотрим, что происходит дальше

Казалось бы, appsee безопасен и скорее всего несколько раз помогал разработчикам улучшать приложение. Но давайте все же проверим, что происходит с данными карты дальше. Для начала необходимо прочитать комментарий представителя Burger King в СМИ по поводу сложившейся ситуации:

«Мобильное приложение Burger King с удаленным заказом не собирает персональных данных своих подписчиков. Все транзакции надежно защищены одним из лучших эквайеров страны — »Яндекс.Касса". Данные о поведении пользователей в приложении не содержат информации о банковских картах и не хранятся на сервере", — сообщает компания.

Звучит достаточно убедительно, а теперь смотрим реальный трафик. Для оплаты действительно используется процессинг от Яндекса, это можно определить по запросу с адресом

https://payment.yandex.net/api/v2/payments/bankCard

Полезной нагрузкой запроса является параметр request с некоторыми данными:

Данные

eyJhbGciOiJFUzI1NiIsImlzcyI6Imluc3RhbmNlSWQ6cHJHa28rRnNnUlhvZnZwWVBiUDRSeVp0bWs1TkxPTElKRGp
EY1FmMVlzSkFPVjNLUGtGRkJJY0QwRFRzL0t5WSIsImlhdCI6IjE1MzEzODYxNDcwMDAifQ.eyJvcmRlciI6eyJjbGll
bnRPcmRlcklkIjoiMmE2ZGEwMTQtMjhlMC00NTYwLWEwNTctNzYxNjBjOGNjM2NhIiwiY3VzdG9tZXJJZCI6IiIsInZh
bHVlIjp7ImFtb3VudCI6IjEuMDAiLCJjdXJyZW5jeSI6IlJVQiJ9LCJwYXJhbWV0ZXJzIjp7ImNhcmRVVUlEIjoiN2E5MDR
lMTgtZDk0NS00MTI4LTgyMDctMTg3ZDFhMDgxYjM0IiwidXNlcklkIjoyNTg1MDQsImFkZENhcmQiOnRydWV9fSwiZ
XhwaXJ5WWVhciI6IjIwMjUiLCJleHRBdXRoRmFpbFVyaSI6Imh0dHBzOi8vb3JkZXJhcHAuYnVyZ2Vya2luZy5ydS9h
cGkvdjEvcGF5L2ZhaWxlZCIsInNvdXJjZSI6IkJhbmtDYXJkIiwicmVjaXBpZW50Ijp7InNob3BJZCI6IjE0NTM2MyIsInNo
b3BBcnRpY2xlSWQiOiI0NDk1MzIifSwiY3NjIjoiMjIyIiwicGFuIjoiMjIyNTU1NTI1NTM2NjY2NiIsImNyZWF0ZVJlY3Vyc
mluZyI6dHJ1ZSwiZXh0QXV0aFN1Y2Nlc3NVcmkiOiJodHRwczovL29yZGVyYXBwLmJ1cmdlcmtpbmcucnUvYXBpL
3YxL3BheS9zdWNjZXNzIiwiZXhwaXJ5TW9udGgiOiIxMCJ9.s0H0pnOyCJTm9NJjyj0Ixg15IlRzYbpW7HboSwwAUDi
y4KCkeIQul14lL8P6ocPNTI_Y3acG4x_vSo8C0T1qtQ

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

{
  "order": {
    "clientOrderId": "2a6da014-28e0-4560-a057-76160c8cc3ca",
    "customerId": "",
    "value": {
      "amount": "1.00",
      "currency": "RUB"
    },
    "parameters": {
      "cardUUID": "7a904e18-d945-4128-8207-187d1a081b34",
      "userId": 258504,
      "addCard": true
    }
  },
  "expiryYear": "2025",
  "extAuthFailUri": "https://orderapp.burgerking.ru/api/v1/pay/failed",
  "source": "BankCard",
  "recipient": {
    "shopId": "145363",
    "shopArticleId": "449532"
  },
  "csc": "222",
  "pan": "2225555255366666",
  "createRecurring": true,
  "extAuthSuccessUri": "https://orderapp.burgerking.ru/api/v1/pay/success",
  "expiryMonth": "10"
}

Логи всему голова

Казалось бы, что может пойти не так, карта должна надежно обрабатываться на Яндекс.Касса. Если бы разработчики приложения Burger King не решили добавить немного логирования со своей стороны. И как будто по мановению волшебной палочки данные о карте отправляются как часть лога, по адресу:

https://orderapp.burgerking.ru/api/v1/log/requests

[{"created_at":1531386147,"entity":"yandex","method":"POST","request_data":"request=eyJhbGciOiJFUzI1NiIsImlzcyI6Imluc3RhbmNlSWQ6cHJHa28rRnNnUlhvZnZwWVBiUDRSeVp0bWs1TkxPTElKRGpEY1FmMVlzSkFPVjNLUGtGRkJJY0QwRFRzL0t5WSIsImlhdCI6IjE1MzEzODYxNDcwMDAifQ.eyJvcmRlciI6eyJjbGllbnRPcmRlcklkIjoiMmE2ZGEwMTQtMjhlMC00NTYwLWEwNTctNzYxNjBjnOGNjM2NhIiwiY3VzdG9tZXJJZCI6IiIsInZhbHVlIjp7ImFtb3VudCI6IjEuMDAiLCJjdXJyZW5jneSI6IlJVQiJ9LCJwYXJhbWV0ZXJzIjp7ImNhcmRVVUlEIjoiN2E5MDRlMTgtZDk0NS00MTI4LTgynMDctMTg3ZDFhMDgxYjM0IiwidXNlcklkIjoyNTg1MDQsImFkZENhcmQiOnRydWV9fSwiZXhwaXJ5nWWVhciI6IjIwMjUiLCJleHRBdXRoRmFpbFVyaSI6Imh0dHBzOi8vb3JkZXJhcHAuYnVyZ2Vya2lunZy5ydS9hcGkvdjEvcGF5L2ZhaWxlZCIsInNvdXJjZSI6IkJhbmtDYXJkIiwicmVjaXBpZW50Ijp7nInNob3BJZCI6IjE0NTM2MyIsInNob3BBcnRpY2xlSWQiOiI0NDk1MzIifSwiY3JlYXRlUmVjdXJynaW5nIjp0cnVlLCJleHRBdXRoU3VjY2Vzc1VyaSI6Imh0dHBzOi8vb3JkZXJhcHAuYnVyZ2Vya2lunZy5ydS9hcGkvdjEvcGF5L3N1Y2Nlc3MiLCJleHBpcnlNb250aCI6IjEwIiwicGFuIjoiKioqKiAqnKioqICoqKiogNjY2NiJ9n.s0H0pnOyCJTm9NJjyj0Ixg15IlRzYbpW7HboSwwAUDiy4KCkeIQul14lL8P6ocPNTI_Y3acG4x_vSo8C0T1qtQ","request_headers":"Content-Type: application/x-www-form-urlencodednContent-Length: 974nHost: payment.yandex.netnConnection: Keep-AlivenAccept-Encoding: gzipnUser-Agent: okhttp/3.10.0n","response_data":"{"status":"Refused","cardAuthorizeResult":{"responseCode":"BL07","rrn":"","authId":""},"error":"InstrumentNotAllowed","parameterName":"country","errorDescription":"Card country is forbidden for this merchant"}","response_error_num":403,"response_error":"{"status":"Refused","cardAuthorizeResult":{"responseCode":"BL07","rrn":"","authId":""},"error":"InstrumentNotAllowed","parameterName":"country","errorDescription":"Card country is forbidden for this merchant"}","response_headers":"403 Content-Type: application/json;charset=UTF-8nDate: Thu, 12 Jul 2018 09:02:28 GMTnConnection: closenContent-Length: 209n","url":"https://payment.yandex.net/api/v2/payments/bankCard"}]

Лог отправляется как при успешной, так и при неудачной попытке вызвать процессинг карты. Это явный прокол разработчиков, теперь, сложно поверить, что данные карт не сохраняются. Почти уверен, что логи сохраняются, иначе зачем их отправлять? :)

Выводы

  1. Аналитика это нормально, конечно, хотелось бы более «яркого» предупреждения. Без аналитики разработка крупных и сложных приложений невозможна.
  2. Данные о картах все же собирают, скорее всего, не умышленно.

Автор: norver

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js