
Спустя несколько дней после начала разработки «одного миллиона чекбоксов» (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/omcbcatgirls точка 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, было очень круто, удивительно и креативно. Это напомнило мне о самом себе в их возрасте; они в десять раз больше разработчики, чем я был тогда (и, честно говоря, лучше разработчики, чем я сейчас). Возможность наблюдать за этим вживую, мотивировать, хвалить их и гордиться ими, а не гневаться, было для меня очень важно. Я всё ещё каждый раз готов расплакаться, вспоминая об этом.
Я горд созданием того, что этот сервер счёл интересным для экспериментов, и ещё более горд тем, что они сделали с моим проектом.
Мне не терпится увидеть, что они сделают ещё.
