Спустя несколько дней после запуска One Million Checkboxes мне показалось, что меня взломали. Что вот это делало в моей базе?
Через несколько часов я был в слезах, тронутый креативностью подростков из интернета.
Но обо всем по порядку.
Что такое One Million Checkboxes?
26 июня 2024 года я запустил сайт под названием One Million Checkboxes (OMCB). На нем был расположен миллион общих чекбоксов: установка или снятие галочки одним пользователем моментально отображались у всех остальных.
Мои ожидания были довольно низкими и оказались абсолютно неверными. Я думал, что несколько сотен игроков нажмут несколько тысяч чекбоксов - вместо этого за две недели, что я держал сайт запущенным, 500 тысяч игроков прощелкали более 650 миллионов чекбоксов. Сайт попал на полосы New York Times и Washington Post, упоминания о нем есть в Know Your Meme и Википедии. Это было сумасшедшее приключение!
В отдельном посте в своем блоге я рассказал про технические детали реализации OMCB. В этот раз я расскажу другую, свою любимую историю, которая произошла во время работы сайта.
Чтобы смысл истории был понятен, необходимо поделиться с вами двумя важными деталями.
Деталь 1: в OCMB сложно рисовать
Я люблю делать игры, которые помогают людям в интернете взаимодействовать между собой. Некоторые люди при взаимодействии в интернете ведут себя, как ушлепки. Поэтому, когда я делаю игры наподобие таких, я стараюсь добавлять ограничения, которые делают типичное взаимодействие чуть более приятным.
Примечание автора 1: статистика из игры Talk Paper Scissors говорит о том, что примерно в 4.5% игр игроки пытались напакостить.
Я достаточно давно этим занимаюсь и отлично знаю, что именно люди начнут рисовать, если дать им полотно, доступное широкой публике. По этой причине я хотел ограничить возможности рисования в OMCB, и сделал количество чекбоксов в строке зависящим от ширины окна браузера. Вот так оно выглядит на практике:
Здесь я написал слово EXAMPLE ("пример" - прим. пер), но его видно только на определенной ширине экрана. Как только ширина окна меняется, сообщение исчезает.
Это значит, что если вы нарисуете что-то непристойное с телефона, я со своего ноутбука это не увижу - и наоборот: ваше граффити увидят только люди с точно таким же размером экрана. Это ограничение особенно нравится мне своей неброскостью: многие люди даже не подозревали, что их надписи не видны никому кроме них.
Я получил огромное количество комментариев с просьбой "починить" это поведение, чтобы люди могли рисовать, однако это было сделано вполне сознательно.
Самые интересные истории из моих игр про взаимодействие с незнакоцами обычно про попытки обойти добавленные мной ограничения. Это небольшой спойлер.
Деталь 2: как я хранил состояние
Из названия понятно, что в OCMB был один миллион чекбоксов. Это большая цифра! Поэтому я хотел хранить и передавать состояние эффективным способом.
У чекбокса есть 2 состояния - он либо включен, либо выключен. Прямо как один бит - либо 1, либо 0. Поэтому я хранил состояние каждого чекбокса в виде соответствующего бита информации: если чекбокс 3 проставлен, бит 3 имеет значение 1, и так далее.
Это миллион битов. В одном байте 8 бит, а значит все состояние занимает 125 КБ - даже меньше, чем MP3-файл! С этим можно работать.
Я хранил данные в Redis (его легко использовать в качестве базы данных) и кодировал их в base64 при передаче на клиент.
Примечание автора 2: это простой способ передавать бинарные данные через интернет. Есть и более эффективные способы, но я не особо парился по этому поводу во время разработки, в первую очередь потому, что не ожидал такой популярности.
Честное слово, это важно! А теперь вернемся к самой истории.
Меня взломали?
Через несколько дней после запуска OCMB я переписал бэкенд на Go (при содействии моего друга Элиота), чтобы справиться за растущей нагрузкой. А потом я вывел данные из базы в виде ASCII-символов - не знаю зачем, просто так.
И данные, которые я увидел, выглядели вот так:
Моя реакция была примерно такой:
Я запаниковал. В моей базе данных были ссылки! Более того, ссылки на какой-то домен с подозрительным названием catgirls.win! Что-то пошло совсем не так.
Я предположил, что меня взломали. Я проглядел логи в поисках следов вторжения. Я вчитывался в исходник снова и снова, пытаясь найти возможность для записи строки в базу, которая должна была содержать просто нули и единицы.
Ничего не было. Логи доступа выглядели нормально. Мой (элементарный) код был в порядке. У меня подскочил пульс. Моя подруга терпеливо ждала, когда я приду ужинать. И тогда я - подождите...
Подождите!
До меня дошло.
Скрытое послание
Я посмотрел на чекбоксы, которые соответствовали палевным ссылкам в базе.
Эта буква H представляла собой 1 байт. Байт состоял из 8 бит. Эти 8 бит соответствовали 8 чекбоксам.
Эти блоки по 8 чекбоксов формировали повторяющийся паттерн, по которому было выравнены ссылки. И если я что-то менял - снимал галочку с чекбокса - паттерн моментально появлялся снова.
Меня не взломали.
Кто-то писал мне послание в бинарном виде.
Что это значит:
Когда я вывел содержимое базы в консоль, Redis сконвертировал его в ASCII.
Для этого он считывает данные по одному байту. Он конвертируется в число от 0 до 255, и если оно соответствует коду печатного символа ASCII (32-127), то печатается как есть, в противном же случае выводится шестнадцатиричное представление (\x00
для 0
).
Значит, кто-то:
Проставлял галочки
Чтобы переворачивать биты
Чтобы формировать числа
Которые представляли собой буквы
Которые складывались в URL
И они делали это при наличии тысяч других пользователей на сайте.
Я был впечатлен.
Глубже в кроличью нору
Итак.
https://catgirls.win/omcb
кошкодевки точка вин
Я долго сомневался. Погуглил. А потом просто нажал на ссылку.
Ссылка вела на Discord. А канал назывался "Нажимаем галочки". Я зашел.
Примечание автора 3: оригинальный канал заблокирован, а ссылка перенаправляет куда-то еще.
Кто-то был очень рад меня видеть! Мы немного пообщались. А потом они задали мне вопрос, который взорвал мне мозг:
Ты уже смотрел на чекбоксы в виде квадрата 1000x1000?
Я ответил отрицательно. Тогда они показали мне, чем они занимаются:
Они скачивали состояние всех чекбоксов и отрисовывали их в виде картинки 1000x1000 пикселей, где пустые чекбоксы представлены белыми пикселями, а проставленные - черными.
Тут много чего происходит. Легко читается фраза "be gay do crime" ("будь геем, совершай преступления" - относительно известный мем, прим. пер.) - угарно - но более интересным для меня были технические детали.
Повторяющийся шум внизу - это то сообщение в бинарном виде, которое я обнаружил. Над ним то же сообщение в виде base64 - помните, что я использовал этот формат для передачи данных. А слева была QR-код (с полной коррекцией ошибок!). Все эти ссылки вели на этот Discord-канал.
В нем сидела компания очень прошаренных подростков, и они писали эти тайные послания, чтобы собрать других прошаренных посетителей и обсуждать написание ботов для сайта. Человек, пишущий бота, скорее всего разглядывал бы сайт в виде base64, или в бинарном виде, или в виде картинки 1000x1000 - они покрыли все варианты.
Примечание автора 4: ну, не только подростков. Но "прошаренных людей моложе меня".
И это сработало. Канал вырос с менее чем 20 человек в момент, когда я туда попал, до более 60 на момент закрытия сайта.
Так что они делали?
Ну, они много рисовали! По мере того, как они усовершенствовали алгоритмы рисования (и разобрались с параметрами моего анти-DDoS-механизма), изображения стали более сложными.
Примечание автора 5: в один момент я предложил сказать им параметры rate limiter'а, но лидер канала ответил, что они хотят угадать их самостоятельно!
Со временем они стали экспериментировать с анимацией и даже добавили протокол для передачи цвета - например, использовать соседние пиксели в качестве красной, зеленой и синей составляющей цвета и рисовать на сетке с меньшим разрешением:
Я отправил в Discord предупреждение перед закрытием сайта. За ночь до этого я убрал все ограничения на частоту запросов чтобы посмотреть, сколько трафика сайт сможет переварить, и что они смогут сделать. В результате получились довольно крутые анимации - мне больше всего понравился рикролл (этот клип не ускорен):
Использовать ботов - хорошо?
Множество людей бесились от наличия ботов на OMCB. Не буду давать прямых ссылок, чтобы не привлекать негативное внимание к кому-либо конкретному - но мне присылали сотни сообщений про ботов. Самый популярный связанный с OMCB твит содержал жалобу на ботов. Боты людям очень не нравились.
И я отлично это понимаю! Обычно люди - особенно те, кто не программирует - сталкиваются с ботами в ситуациях, когда те сметают все доступные билеты или места в ресторанах. Эти боты эгоистичны, бесчестны и антисоциальны.
И разумеется, там были боты, которые можно назвать антисоциальными. Кто-то написал маленький скрипт на JS, который снимал все проставленные галочки - я об этом знаю, потому что они сами с возбуждением мне об этом рассказали.
Я этого ждал - я же программист! - но люди говорили, что это испортило им все впечатление от сайта, и наверное я могу это понять.
Так что, да. Рисование ухудшало опыт для "обычных" пользователей - хотя у ботоводов были правила касательно того, какие сегменты можно трогать, и я иногда приходил с просьбой умерить пыл:
всем привет, сайт попал в washington post (бугага), если вы ботоводите в верхней части сетки, куда будут приходить люди и кликать на случайные галочки, приостановите это на какое-то время чтобы нормальные люди могли повеселиться хехе (думаю что большинство людей эту часть не трогают, просто напоминание)
Насколько хорошо это сработало - вопрос открытый.
Так что проблемы были. Я понимаю, почему люди не любят ботов, может это и правда не было неоспоримым благом, но честное слово...
Это было так трогательно!
В старшей школе я написал рекурсивное правило перенаправления почты, которое в шутку отправило моему другу миллионы сообщений. Я (совершенно случайно!) несколько раз ронял школьный почтовый сервер.
Примечание автора 6: про это я когда-нибудь напишу отдельный пост.
Взрослые, как правило, на меня не ругались. Они просили меня завязывать, но иногда награждали футболками. Думаю, что я бы не занимался всем этим сейчас без того поощрения, которое я получил от них тогда.
Примечание автора 7: одним из таких взрослых был мой учитель информатики - замечательный Ричард Айзенберг, который впоследствии стал блестящим исследователем в области функционального программирования и моим будущим коллегой в Jane Street.
То, что народ сделал в этом дискорде было очень круто - очень неожиданно - очень креативно. Они напомнили мне самого себя - с оговоркой, что они в десять раз круче, чем я был тогда (и, если по-честному, наверное круче чем я сейчас). Иметь возможность наблюдать это вживую - возможность поощрить, увидеть их действия и ответить похвалой и гордостью вместо гнева - было для меня очень важно на каком-то глубоком уровне. У меня до сих пор наворачиваются слезы, когда я об этом думаю.
Я горжусь тем, что сделал нечто, заинтересовавшее этих ребят. Еще больше я горжусь тем, что они в итоге построили.
И очень хочу узнать, что еще они придумают в будущем.