Спустя несколько дней после начала разработки «одного миллиона чекбоксов» (One Million Checkboxes, см. новость на Хабре) я решил, что меня взламывают. Что это делает в моей базе данных?

Спустя несколько часов я уже лил слёзы гордости за талантливых подростков.

Но вернёмся к началу.

Что такое One Million Checkboxes?


26 июня 2024 года я запустил веб-сайт под названием One Million Checkboxes (OMCB). На нём был один миллион глобальных чекбоксов — нажатие на чекбокс мгновенно переключало его состояние для всех на сайте.


Вот как выглядел сайт через полчаса после запуска

Мои ожидания от этого сайта были крайне малы и совершенно ошибочны. Я думал, что сотни игроков будут нажимать тысячи чекбоксов, однако за две недели работы сайта пятьсот тысяч игроков нажали на флажки более 650 миллионов раз. Сайт попал в новости New York Times и Washington Post; он есть в Know Your Meme и Википедии. Это было безумное приключение.

В отдельном посте я поделился техническими подробностями OMCB. А в этом посте я расскажу свою любимую историю о работе этого сайта.

Но прежде чем рассказывать историю, нужно немного ввести вас в контекст.

Контекст 1: я сделал так, чтобы в OMCB было сложно рисовать


Я люблю делать игры, помогающие людям взаимодействовать в Интернете. Некоторые люди при общении в Интернете ведут себя как засранцы. Поэтому создавая игры наподобие этой я стараюсь добавить ограничения, чтобы в среднем общение было чуть более приятным.

[По статистике, собранной в Talk Paper Scissors, примерно в 4,5% игр кто-то пытался вредничать.]

Я не вчера родился, и понимаю, что если выложить в публичный Интернет неограниченный холст, то люди начнут на нём рисовать, поэтому в OMCB я хотел усложнить рисование.

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


Здесь написано EXAMPLE, но увидите вы это, только если окно браузера ровно нужной ширины! Как только количество чекбоксов в строке меняется, сообщение пропадает.

То есть если вы напишете что-то грубое на своём телефоне, то это не будет видно на моём ноутбуке, и наоборот: ваше граффити будет видно только людям с точно таким же дисплеем, что и у вас. Это ограничение было особенно красиво благодаря своей малозаметности; вы можете никогда и не догадаться, что написанное вами не видно больше никому на сайте!

Мне пришла куча комментариев с просьбой «исправить» это, чтобы люди могли писать. Но сделал я это абсолютно намеренно.

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

Это стало предвестьем.

Контекст 2: как я хранил состояние


В OMCB был миллион чекбоксов. Миллион — это много! Поэтому я хотел хранить и передавать состояние эффективным образом.

Для этого я принял, что чекбокс имеет два допустимых состояния: включен и отключен. То есть это похоже на бит: он имеет значение 0 или 1. Поэтому я просто хранил состояние каждого чекбокса в бите. Бит 3 имел значение 1, если чекбокс 3 был включен, и 0 в противном случае.

Это миллион битов. В байте 8 битов, то есть это 125000 байтов, или 125 КБ — даже меньше размера MP3! С этим без проблем можно работать.


Включенные чекбоксы — это 1, отключенные — 0

Я хранил эти данные в Redis (простой в использовании базе данных), а при передаче клиентам кодировал в base64.

[Это простой способ передачи двоичных данных в Интернете. Существуют более эффективные варианты, но я особо не заморачивался ими при создании OMCB, в первую очередь потому, что не ожидал такой её популярности.]

Обещаю, что это будет важно. А теперь вернёмся к истории.

Меня взломали?


Спустя несколько дней после запуска OMCB я переписал бэкенд на Go (мне помогал в этом мой друг Элиот), чтобы сайт справлялся с нагрузкой. Затем по какой-то причине я сдампил ASCII-кодировку сырых байтов в мою базу данных. Не знаю, зачем я это сделал, просто сделал.

Данные выглядели вот так:


Какого?..

Моя реакция на эти данные была примерно такой:


Я запаниковал. В моей базе данных есть куча URL! В моей базе данных есть URL, ведущие на catgirls.win! Что-то где-то сильно пошло не так.

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

Я не смог ничего найти. Логи доступа выглядели обычно. Мой код (очень простой) не содержал ошибок. Мой пульс участился. Моя девушка терпеливо ждала, пока я присоединюсь к ней за ужином. Но потом… постойте-ка.

Постойте-ка!

Я это увидел.

Скрытое сообщение


Я посмотрел на чекбоксы, соответствовавшие подозрительным URL в моей базе данных.


«h» — это один байт, 8 битов. 8 чекбоксов. Эти 8 чекбоксов

Эта H обозначает один байт. Один байт — это 8 битов. 8 битов — это 8 чекбоксов.

Эти блоки по 8 чекбоксов образовывали повторяющийся паттерн, совпадавший с адресами URL. А если я что-то менял, например, отключал чекбокс, паттерн мгновенно появлялся заново.


Жуть

Меня не взломали.

Кто-то отправлял мне сообщение двоичным кодом.

Что это значит?


Когда я сдампил мою базу данных, Redis преобразовал данные в ASCII.

Для этого он считывал по одному байту (8 битов) данных за раз. Затем он преобразовал этот байт в число от 0 до 255 (28 — 1). А затем проверил, находится ли это число в диапазоне печатаемых символов ASCII (32-127). Если находится, он выводил соответствующий символ; в противном случае он выводил байт в шестнадцатеричном виде (например, \x00 для 0).



104 обозначает «h», а 116 обозначает «t»

То есть кто-то:

  • Нажимал на чекбоксы
  • Чтобы переключать биты
  • Чтобы создавать числа
  • Преобразуемые в буквы
  • Из которых состоит URL

И всё это он делал, когда на сайте были тысячи других людей.

Меня это впечатлило.

В кроличью нору


Итак.

https://catgirls.win/omcb

catgirls точка win

Я колебался и терзался. Гуглил. А потом нажал на ссылку.


Любопытно

Ссылка вела на Discord! И сервер Discord назывался «Checking Boxes». Я присоединился к серверу.

[Исходный сервер уже заблокирован, а URL указывает на что-то другое.]


Меня приветствуют

И кто-то был очень рад меня видеть! Мы немного поболтали. А потом он задал мне вопрос, который взорвал мой мозг:

«Ты уже смотрел на свои чекбоксы как на изображение размером 1000x1000?»

Я сказал, что нет. Он показал мне, к чему был этот вопрос:


Ничего себе

Они скачивали данные всех миллионов чекбоксов и рендерили их в сетке 1000x1000 (отключенные чекбоксы белые, включенные — чёрные).

Тут много всего интересного! «be gay do crime», но и разные интересные технические штуки.


Повторяющийся шум внизу — это найденное мной двоичное сообщение. Выше находится версия того же сообщения в base64 — вспомним, что я использовал base64 для передачи. А слева находится QR-код (с полной коррекцией ошибок!). Все эти сообщения вели на Discord.

На сервере Discord была целая куча очень умны�� подростков, они писали эти секретные сообщения другим очень умным подросткам, чтобы обсудить взаимодействие с сайтом при помощи ботов. Те, кто писали ботов, увидели бы закодированные base64 данные, двоичную версию или изображение 1000x1000; они предусмотрели все варианты.

[На самом деле, там присутствовали не только подростки. Но это определённо были «умные люди младше меня».]

И это сработало! Когда я пришёл на сервер в первый раз, там было меньше двадцати человек, а когда я закрыл сайт, он разросся до более чем шестидесяти.

Что же они делали?


Они рисовали! В процессе совершенствования систем для рисования (и реверс-инжиниринга моих ограничений частоты запросов) их рисунки становились всё сложнее.


Синий экран смерти Windows, ещё до инцидента с CrowdStrike!

Они экспериментировали с анимациями и даже пробовали использовать протоколы, чтобы добавить цвета, например, обрабатывать соседние ячейки как каналы красного, зелёного и синего, а рисовать на сетке меньшего размера.


Сетка почти хаотична, кто-то был фанатом Джейка Джилленхола.

Перед тем, как закрыть сайт, я вывесил на сервере Discord предупреждение. В ночь перед отключением я снял все ограничения частоты запросов, чтобы узнать, с каким объёмом трафика может справляться сайт и на что способны они. В результате мы создали очень крутые анимации, мне больше всего понравился рикролл (этот клип не ускорен).


Ботоводство — это хорошо?


Многих людей раздражали боты на OMCB. Я не буду указывать ссылки, потому что не хочу привлекать к кому-либо негативного внимания, но я получил сотни сообщений о ботах. Самый популярный твит об OMCB был жалобой на ботов. Скажем так, люди не любили ботов.

И я их понимаю! Чаще всего люди сталкиваются с ботами (особенно те из них, кто не программирует), когда кто-то скупает все билеты, чтобы спекулировать ими, или бронирует места в ресторанах. Ботоводство кажется эгоистичным, нечестным и антисоциальным явлением.

И, разумеется, на моём сайте были боты, которые можно назвать антисоциальными. Люди писали небольшие Javascript-чекбоксы, позволявшие отключать все возможные чекбоксы. Я знаю об этом, потому что они сами с восторгом об этом рассказывали мне.


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

Так что да, вероятно, это рисование мешало «обычным» пользователям, однако у ботоводов всё-таки были правила о том, где можно использовать ботов, и я сам время от времени просил их умерить активность.


Не знаю, насколько это сработало

Так что есть определённые изъяны. Я понимаю, почему люди не любят ботов; возможно, ботоводство — это небесспорное поведение. Но…

Как же это меня тронуло!


В старшей школе в качестве шутки я написал рекурсивное правило, отправлявшее моему другу миллионы писем. Я (случайно!) многократно ломал почтовый сервер школы.

Взрослые, которые были в моей жизни, в целом не злились на меня. [В том числе и мой учитель информатики, невероятный Ричард Эйзенберг, который позже стал потрясающим исследователем функционального программирования и моим будущим коллегой в Jane Street!] Они просили прекратить, но и подарили мне футболку. Не думаю, что сейчас бы я занимался тем, что делаю, если бы не полученная в то время мотивация.

То, что сделали на сервере Discord, было очень круто, удивительно и креативно. Это напомнило мне о самом себе в их возрасте; они в десять раз больше разработчики, чем я был тогда (и, честно говоря, лучше разработчики, чем я сейчас). Возможность наблюдать за этим вживую, мотивировать, хвалить их и гордиться ими, а не гневаться, было для меня очень важно. Я всё ещё каждый раз готов расплакаться, вспоминая об этом.

Я горд созданием того, что этот сервер счёл интересным для экспериментов, и ещё более горд тем, что они сделали с моим проектом.

Мне не терпится увидеть, что они сделают ещё.