Последствия drop table: Как «Печкин» пережил серию атак инсайдеров, выжил и стал лучше
В интернете можно найти немало историй о том, как акционерные конфликты в компаниях ставили их на грань выживания — однако чаще всего такие случаи кажутся чем-то далеким и никак не влияют на повседневную жизнь. В последние пару месяцев многие пользователи сервиса «Печкин» сталкивались с проблемами при работе с ним — и в нашем случае страшилки из бизнес-СМИ стали реальностью, чуть не похоронив весь проект.
Сегодня мы расскажем о том, как столкнулись с серией хакерских атак со стороны инсайдеров в компании, пережили их последствия и смогли сделать сервис лучше.
Предыстория
Проблемы начались с акционерного конфликта между создателями сервиса «Печкин» и инвесторами, выкупившим проект. Не будем вдаваться в детали возникших разногласий (это тема для отдельного и не самого короткого материала), скажем лишь, что в конечном итоге бывший владелец в один момент сообщил о том, что он и вся его команда больше работать с новой командой не будут, и исчез, не оставив ни паролей, ни документации, ни каких бы то ни было рекомендаций по работе с имеющейся инфраструктурой.
После этого стало ясно, что события могут начать развиваться и по очень неблагоприятному сценарию, однако мы надеялись, что у нас хотя бы будет время на то, чтобы немного вникнуть в код и разобраться с архитектурой системы. Однако этого времени у нас не оказалось.
Ночная атака и оборона
17 апреля текущего года около 2 часов ночи было получено системное уведомление о «падении» сервиса «Печкин». Дежурный администратор даже не сразу понял, что именно случилось — для части ключевых таблиц проекта (их несколько сотен тысяч) была выполнена команда drop table. По сути, это означало полное удаление некоторых пользовательских данных. Одновременно оставшиеся таблицы были переименованы для затруднения дальнейших разбирательств. При этом размер БД составлял около 1,5 терабайт, так что только ее копирование для дальнейших манипуляций должно было занять около 30 часов.
Разумеется, для всех удаленных таблиц имелись бэкапы базы — полный, инкрементальный и бинлоги. Этого должно было хватить: полный бэкап был за 20 марта, с этого дня до 2 апреля у нас был инкрементальный бэкап, а с 2 по 17 апреля имелись бинлоги.
Важный момент — 17 апреля был выходным днем (воскресенье), так что команде пришлось в срочном порядке выходить на работу, чтобы попытаться хоть как-то восстановить работу сервиса и ответить на гигантский поток обращений от клиентов, обрушившийся на отдел поддержки. К сожалению, глубокого понимания структуры базы данных у специалистов на тот момент не было, что усложняло работу и приводило к ошибкам — например, часть таблиц была «сломана» и в бэкап попали уже «битые» данные.
Были сделаны несколько копий БД — это позволило «накатывать» бэкапы без риска испортить исходные данные. Мы начали процедуру восстановления —, но она должна была занять много времени. Сотни тысяч таблиц, огромный объём — только на восстановление бинлогов требовался в лучшем случае день, а с каждым часом потери бизнеса только увеличивались.
Пользователи были в гневе, и их можно понять. Число тикетов поддержки быстро достигло 3000 — пришлось настраивать автоответы, чтобы хоть как-то объяснить каждому из написавших нам, что в действительности произошло.
Предстояло решить главный вопрос: начинать работу с данными за 20 марта или попробовать совершить невозможное и восстановить все на момент падения сервиса. Мы решили бороться за данные каждого пользоваться до конца. Но требовалось подкрепление, поэтому пока члены команды работали изо всех сил, руководство проекта в авральном режиме за день нашло сильного DBA-специалиста — уже ночью того же дня он присоединился к пожарной бригаде в деле восстановления БД таблицы за таблицей. К сожалению, даже при всем этом полное восстановление заняло еще 4 дня —, но в итоге у нас были все данные до последней email-кампании!
Как вообще это стало возможным
Первый вопрос, который возникает после прочтения всего вышенаписанного — как вообще удаленное выполнение команды удаления в БД стало возможным? Ответ сколь прост, столь и неприятен — бывший владелец сервиса оставил в коде «бэкдор», подложив скрипт, с помощью которого можно было получать доступ к базе и запускать команды (тот же drop table).
Как мы уже писали, проект оказался в ситуации акционерного конфликта, поэтому мы ожидали возможных атак и готовились к ним. Однако обнаружить все дыры безопасности просто не удалось — технический директор проекта вместе с разработчиками около четырех суток чистили код от потенциально уязвимых мест, но тот, кто этот код писал, все равно оказывался на шаг впереди. Именно поэтому уже после восстановления после ночной атаки на «Печкин» была произведена еще серия нападений, которые приводили к кратковременных падениям сервиса и отказу ряду его функций.
К каким изменениям это приведет
Для того, чтобы предовтратить повторение подобных проблем, мы укрепили оборону «Печкина». Однако даже сейчас гарантировать безопасность на 100% невозможно — все еще есть люди, которые знают код лучше текущей команды и хотят уничтожить проект. Поэтому старый «Печкин» вскоре прекратит свое существование, а на смену ему придет новый более стабильный и современный продукт.
Это произойдет уже в самое ближайшее время. Вряд ли процесс перехода будет легким — пользователи привыкли к старому интерфейсу и многим полезным функциям системы, такая революция вряд ли понравится всем. Тем не менее, мы убеждены, что главная задача сервиса рассылок — доставлять письма в инбокс подписчикам без сбоев и по расписанию. И чтобы гарантировать это, изменения необходимы.
Чему это нас научило: главные выводы
И в заключение, сформулируем советы, которые, возможно, помогут кому-то избежать наших проблем в будущем.
- Покупать сервис у разработчика — плохая идея, а у плохого разработчика — очень плохая идея.
- Структура базы данных должна быть такой, чтобы в случае повреждений ее можно было восстановить в течении двух часов, а не дней.
- Проводить аудит кода, заказывать тестирование на проникновение (пентест) у профессиональных «белых хакеров» — это гораздо дешевле, чем восстанавливать подпорченную репутацию и терять клиентов.
Кроме того, перечислим несколько мыслей по оптимизации структуры базы данных:
Следует избавляться от неэффективного шардинга — шардинг имеет смысл, когда таблицы разносятся по разным инстансам БД, на разные сервера. Шардинг на уровне каждого пользователя, особенно при огромном количестве таблиц — за гранью добра и зла. Огромное количество небольших таблиц приводит к существенному перерасходу дискового пространства из-за высокой степени фрагментации мелких таблиц.
Объединение все в один набор таблиц даст выигрыш по диску от 1,5 до 2 раз. При этом не нужно бояться больших таблиц. Грамотная структура и использование ключей позволят сохранить высокую скорость работы.
Старые данные нужно выгружать в архив — стоит задуматься над сохранением устаревших данных в архивную БД. Это резко сократит размер базы, уменьшит потребление памяти и диска, ускорит работу mysql.
Стоит отказаться от инкрементальных бэкапов в пользу бинарных логов — в нашем случае двухнедельный инкрементальный бэкап занимал 400 гигабайт, в тоже время бинлоги за 2 недели имели объем в 20 гигабайт. Огромный размер бэкапа объяснялся в том числе и большим количеством таблиц. По нашему мнению, инкрементальный бэкап — это ненадежный, сложный в эксплуатации инструмент, не имеющий никаких достоинств перед обычными бинарными логами.
Важно сохранять mysqldump-файлы копий бэкапа — как и в случае бинлогов, преимущества таких дампов в надежности. Даже если файлы окажутся битыми, большой процент данных все равно можно будет восстановить. Сжатие же позволит хранить достаточное количество бэкапов, а с учетом архивной базы данных — еще больше. Это не отменяет использование xtrabackup, но mysqldump станет хорошим дополнением в арсенале инструментов резервного копирования.
На сегодня все, спасибо за внимание. Мы будем рады ответить на все вопросы в комментариях.