[Перевод] Как освободить умные часы Garmin от облачных сервисов, которые не работают из-за атаки

Автор статьи — известный хакер Эндрю Хван (bunnie)

Я часто говорю: если поверить, что технология — это магия, то мы рискуем стать её заложниками. Совсем недавно я попал в такую ситуацию, но, к счастью, меня спас открытый исходный код.

На момент написания этой статьи Garmin страдает от массированной атаки зловреда-вымогателя. Это повлияло на меня, потому что у меня есть часы Garmin Instinct. Я очень доволен ими, и во многих отношениях они просто волшебны, так много возможностей упаковано в такой крошечный гаджет.

Кроме того, у меня есть хобби — гребля на каноэ с выносными опорами.

Я считаю, что GPS-часы — незаменимый элемент безопасности, особенно в навигации, потому что трудно судить о скорости воды, когда вы находитесь более чем в нескольких сотнях метров от земли. Если вы попали в плохое течение, без понимания ситуации вас рискует выбросить в море или того хуже.
Вокруг Сингапура могут быть экстремальные течения. При смене приливов и отливов Южно-Китайское море в конечном итоге находит путь в Андаманское море через Сингапурский пролив, вызывая предательские течения, которые меняются с течением времени. Поэтому после каждого гребка мои GPS-данные загружаются в облако Garmin Connect для просмотра маршрута, чтобы отметить опасные изменения в характере течений с приливами и отливами.

Хотя загрузка таких данных в облако Garmin представляет собой явный и реальный риск для конфиденциальности, мы все понимаем компромисс: времени мало, чтобы беспокоиться о таких вещах, а сервис из коробки хорошо работал.

До вчерашнего дня.

Мы как раз попали в особенно необычные течения, и мой партнёр по гребле захотел посмотреть скорости в некоторых сложных местах. Я зашёл в приложение, чтобы получить данные и… ну, я узнал, что компанию Garmin атаковали.

af06d4c4ada2feac279d8f4cad3b3555.png

Данные Garmin взяты в заложники, в том числе мои персональные данные о гребле: маленькая часть моей жизни стала заложницей технологий.

Куча друзей посоветовали попробовать Strava. Хорошая новость в том, что Garmin позволяет извлекать файлы данных из часов Instinct для загрузки в сторонние службы. Нужно только подключить часы к обычному USB-порту, и они отобразятся как mass storage device.

Плохая новость в том, что, когда я попытался создать учётную запись на Strava, сработали все красные флаги. Веб-сайт полон тёмных шаблонов, а после нажатия кнопки «Запретить Strava доступ к моим данным, связанным со здоровьем», появилась целая серия диалоговых окон:

69f3af5aca527e55ea58424b3ea0d23a.png

Нажимаем «Отклонить»…

01eb8f8d1ab681fd70110987203e4837.png

Нажимаем «Запретить разрешение»…

36db66dfe73964cfae3a8ff43f436437.png

Нажимаем «OK»…

Три клика, чтобы запретить доступ, а если расслабленно продолжать нажимать нижнюю кнопку, то вы сделаете другой выбор — случайно. После этого меня встретил жуткий список людей, за которыми нужно следить (они так много узнали обо мне по одному адресу электронной почты? ), а затем хитрое диалоговое окно, где если вы ответите неправильно, вам предложат ввести информацию о кредитной карте в рамках «бесплатной пробной версии».

Поскольку Garmin уже заработал на продаже девайса дороже 200 долларов, сбор моих личных данных — просто десерт;, а вот для Strava мои данные — основное блюдо. Лично мне совершенно ясно, что Strava даёт понять своим инвесторам, что они получат большую прибыль, монетизируя мои личные данные, включая информацию о моём здоровье.

Для меня это абсолютно неприемлемо. Вместо того, чтобы освободить данные из залога, переход от Garmin к Strava похож на переход из сковороды прямо в огонь.

Я планирую снова выйти на лодке послезавтра, и было бы здорово получить аналитику по скорости. Но меня настолько рассердила Strava, что я уже не искал другой вариант, а решил разработать собственную альтернативу с надёжной защитой персональных данных.

Я с радостью обнаружил опенсорсную утилиту под названием gpsbabel (спасибо разработчикам! я задонатил! ), которая конвертирует данные из полу-(?)проприетарного формата Garmin в совместимый формат .GPX. Оттуда я смог вычленить фрагменты парсинга XML и объединить его с OpenStreetMaps через Folium API для создания кастомных карт с моими данными.

Даже с учётом того, что я «заблудился» в попытке использовать Google Maps API, которые ставят ужасные водяные знаки «только для разработки» на всех тайлах карты, работа заняла всего один вечер. Не самая лучшая трата моего времени, учитывая все обстоятельства, но в основном это был вопрос поиска правильных опенсорсных частей и склеивания их вместе в Python (кстати, Python — отличный клей, но ужасный структурный материал. Не создавайте из него большие проекты). Качество кода довольно дерьмовое, но Python позволяет это, и он делает своё дело. Учитывая эти предостережения, можно использовать его в качестве отправной точки для поиска чего-то получше.

Теперь я полностью контролирую свои данные и могу осмысленно их визуализировать. Например, вывести скорость как тепловую карту на протяжении всего курса с кругами, пропорциональными скорости в данный момент, и текстом, который при наведении курсора показывает конкретную скорость и частоту сердечных сокращений в данный момент:

432cc5269a01b8b0b694a33824b7c6d4.png

Это конкретно нужные мне данные в нужном формате, не больше и не меньше. Кроме того, выдача представляет собой один html-файл, на который можно поставить прямую ссылку. Никакой аналитики, никаких кукисов. Только те данные, которыми я решил поделиться с вами.

Вот фрагмент кода, который я использую для построения картографических данных:

def plot_osm_map(track, output='speed-map.html', hr=None):
    for i in range(len(track['speed'])):
        track['speed'][i] = speed_conversion(track['speed'][i])
    speeds = track['speed']
    minima = min(speeds)
    maxima = max(speeds)

    norm = matplotlib.colors.Normalize(vmin=minima, vmax=maxima, clip=True)
    mapper = cm.ScalarMappable(norm=norm, cmap=cm.plasma)
    m = folium.Map(location=[track['lat'][0], track['lon'][0]], zoom_start=15)
    for index in range(len(track['lat'])):
        if track['speed'][index] == 0:
            track['speed'][index] = 0.01
        else:
            track['speed'][index] = track['speed'][index]
        if hr:
            try:
                tooltip=str(track['speed'][index]) + ' ' + str(hr['hr'][index]) +'bpm'
            except:
                tooltip=str(track['speed'][index])
        else:
            tooltip=str(track['speed'][index])
        folium.CircleMarker(
            location=(track['lat'][index], track['lon'][index]),
            radius=track['speed'][index]**2 / 8,
            tooltip=tooltip,
            fill_color=matplotlib.colors.to_hex(mapper.to_rgba(track['speed'][index])),
            fill=True,
            fill_opacity=0.2,
            weight=0,
        ).add_to(m)

    m.save(output)


Как я уже сказал, код не самого лучшего качества, но он работает, и его было быстро написать.

Ещё лучше то, что я больше не загружаю никакие данных в облако — есть определённое неосязаемое удовольствие в том, чтобы удалить ещё один канал слежки в моей жизни, ничего не теряя в качестве или удобстве.

Это также интересная метаистория о том, насколько сегодня хорошо себя чувствует опенсорсная экосистема. Когда упало облако Garmin, я смог заменить самые важные функции всего за один день, собрав вместе различные фреймворки с открытым исходным кодом.

Смысл открытого исходного кода не в том, чтобы ритуально компилировать материал. Смысл в осознании, что технология — это не магия: что есть альтернатива, которую каждый может выбрать для себя, чтобы освободиться от потенциальной ситуации с заложниками. Если мы этого хотим, open source даёт возможность создавать и запускать собственные инструменты и сервисы.

© Habrahabr.ru