![](http://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/avatars/00e/955/57a/00e95557ad511da9034aa993ee28d354.jpg)
Как спрятать мусор в базе Spotify и превратить это в квест
![Опасный хакер прячет Spotify-код с секретной информацией Опасный хакер прячет Spotify-код с секретной информацией](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/72a/9b8/192/72a9b81928d88859bf8ffbe1c890dcbf.png)
Введение
Одной бессонной ночью мы с приятелем разговорились о Spotify-кодах.
Это такие картинки, которые можно отсканировать приложением и попасть на нужный трек/альбом/плейлист. Придуманы они, чтобы люди могли делиться музыкой в социальных сетях или в оффлайне.
![Пример. Такая грусть у меня играет прямо сейчас. Пример. Такая грусть у меня играет прямо сейчас.](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/2e6/025/66f/2e602566fc2807f9c547ff91b49ada50.jpg)
Мы решили разобраться, как же Spotify кодирует в них ссылки.
Как работают коды?
Выяснилось, что помимо меню «Поделиться» в приложении, есть официальный сайт Spotify Codes, который генерирует такие коды.
![](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/811/929/c43/811929c43b1ba99706d7d2775419cb06.png)
Если скопировать ссылку на картинку с этого сайта, получится что-то такое: https://scannables.scdn.co/uri/plain/jpeg/000000/white/640/spotify:track:5jxN9knH0vlfpN2Ft7a5xi
Прекрасно! Динамическая ссылка, которая принимает на вход ID трека и возвращает изображение с баркодом — самое то для наших экспериментов.
Очень удобно, что генератор может рисовать коды и в SVG. Это позволило без головной боли понять, что столбики бывают восьми разных высот.
![Числа в поле height — высоты столбиков Числа в поле height — высоты столбиков](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/507/10b/d51/50710bd517be24cc0dd549e78a3592e6.png)
Первый и последний столбик всегда минимального размера, так что он, видимо, используется для ориентирования при сканировании, как и логотип Spotify, который на картинке всегда слева. Без них ничего не работает.
![Важные данные выделены красным Важные данные выделены красным](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/3d3/b20/6d2/3d3b206d2abb0134e0ce7c217caab6f2.png)
Получив число 556205622371746371156, приложение превращает его в 58992959842 с помощью таблицы Грея. Именно это делает распознаванием таким быстрым и устойчивым к ошибкам. Как узнали? К этому моменту мы уже набрели на патент Spotify, описывающий принцип работы таких кодов.
Остался последний вопрос: как же приложение превращает лаконичное 58992959842 в spotify:track:5jxN9knH0vlfpN2Ft7a5xi?
Очевидно, такое число не может вместить в себя все комбинации длинного цифро-буквенного ID, а значит никакого алгоритма нет и соответствие между кодом и ID трека хранится где-то в базе.
Можно проверить, подсунув генератору какой-нибудь очень длинный мусор, который точно не влез бы в число: https://scannables.scdn.co/uri/plain/jpeg/000000/white/640/spotify:track:thisisaverylongidentifierwhichwoulddefinitelyoverflowthatnumericcode
Сработало. Печально, а ведь было интересно научиться кодировать/раскодировать такие картинки полностью самостоятельно.
Решила проверить обмен приложения с сервером в момент распознавания и догадка подтвердилась:
![На сервер уходит 58992959842, а возвращается трек 5jxN9knH0vlfpN2Ft7a5xi На сервер уходит 58992959842, а возвращается трек 5jxN9knH0vlfpN2Ft7a5xi](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/a54/246/5a6/a542465a6060f30ecfe6fffbc7c8b309.png)
Скука: дальше всё происходит за ширмой бэкенда. Расходимся?
Оченьдлинныймусор
Стоп, что? Генератор сделал картинку для оченьдлинногомусора?
Вероятно, он не проверяет реальность входных данных и бережно складывает наш мусор в базу, присваивая ему 11-значный числовой ID.
![Картинка с мусором из примера выше Картинка с мусором из примера выше](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/b7f/9a6/6c0/b7f9a66c0f7536c3ef91b0c2a88c1b6c.jpg)
А что будет, если считать такой код приложением?
![Будет ошибка Будет ошибка](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/b8c/2f3/05d/b8c2f305d65bacd9fcbd789b49026dd1.jpg)
Это ожидаемая реакция. Наверное, сервер уже проверил и инвалидировал некорректный код. Интересно посмотреть, как выглядит такая ошибка, поэтому загляну в трафик ещё раз:
![Эм, что? Эм, что?](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/80d/9f2/db1/80d9f2db152ca00b2d53e86d33666cf7.png)
Великолепно. Spotify складывает в базу всё, что мы укажем в запросе к генератору, хранит это там, а при сканировании отдаёт обратно в первозданном виде, никак не валидируя.
Идея сделать из этого квест для любителей реверс-инжиниринга возникла уже где-то здесь, но он получился бы слишком скучным: ошибка при сканировании сразу наводила на мысли.
Всё лучше под музыку
Чтобы всё было аккуратно, нужно заставить приложение играть музыку, несмотря на чужеродные данные в ID трека.
Я уже собралась реверсить обфусцированный код Android-приложения, чтобы узнать, как работает парсер, но приятель предложил попробовать разделять музыкальный ID и нашу полезную нагрузку знаком вопроса. Идея сработала, но знак пришлось дважды пропустить через urlencode. Например, spotify:track:2ctvdKmETyOzPb2GiJJT53%253Fhi,habr!, выглядит вот так:
![Код с двойным дном Код с двойным дном](https://webcf.waybackmachine.org/web/20200914093451im_/https://habrastorage.org/getpro/habr/upload_files/451/18c/810/45118c81048f2b277bdd5eaaffa3870a.jpg)
Такой код приложение считает как положено и включит песню, а посмотрев в трафик можно достать спрятанные данные, что и стало корнем моего квеста. Для удобства можно закодировать данные в Base64, влезет в URL их немало.
Выводы
Почему Spotify позволяет хранить в базе мусор? Вероятно, потому что генерацией и распознаванием кодов занимается отдельный микросервис, который должен отвечать моментально. Проверка на существование трека потребовала бы обращения к основному бэкенду, а это ресурсоёмкая задача.
Навредит ли это Spotify? Теоретически эта особенность позволяет заполнить таблицу соответствий кодов и исчерпать всю ёмкость, сломав генерацию картинок для настоящих треков, но на практике это займёт очень много времени. Я посчитала.
Полезно ли это на практике? Не знаю, как это использовать. Можете прятать номера телефонов любовниц в кодах с Егором Летовым и обклеивать ими стены, тогда ваша законная женщина покинет вас, сочтя сумасшедшим, будете свободны. Только имейте в виду, что запрос к API для считывания кода, к сожалению, требует авторизационный токен Spotify-аккаунта, в отличие от запроса для генерации картинки.
Оригинальный квест был здесь, послание было в Base64. Кто-то прошёл его за 42 минуты. На большее я не рассчитывала: имеющие привычку лезть в трафик приложений догадались бы сразу.
Помогал думать, предполагал хранение кодов в базе и решил добавить в ID знак вопроса приятель Эль.
Комментарии 4
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.