Страница 1 из 1

10+ способов обрушить mysql-сервер

Добавлено: 27 апр 2010, 11:13
Raven
Иногда у меня спрашивают о ошибках MySQL, (например таких), которые могут привести к обрушиванию mysql-сервера пользователем с обычными привелегиями. Потом звучит вопрос: "Что же делать в таких случаях? Как защититься от подобных ситуаций?" Мой ответ "Сядьте и расслабтесь :)"

Действительно, существует очень много ситауций, в которых сервер падает или не отвечает на запросы. Причем ситуации эти существуют для любых версий MySQL и их можно воспроизвести, обладая базовыми привелегиями для доступа к sql-серверу.
Мы часто помогаем людям исправлять ошибки в их приложениях, используюших MySQL (но положа руку на сердце можно сказать - в большинстве случаев они сами являются причиной некорректной работы сервера) и ощибки эти очевидны.

По-моему, девиз безопасности MySQL должна выглядеть так: если у вас полностью закрыт доступ к серверу, вы действительно защищены. Для некоторых видов атак не нужен валидный аккаунт, но такие ошибки довольно быстро исправляются. В тот момент, когда вы даете кому-то аккаунт вы перестаете полностью контролировать ситуацию. И значит, что защищенность сервера становится немного ниже.

Такое положение вещей будет сохраняться все время, пока MySQL использует Глобальное Управление Ресурсами, и вы реально не можете контролировать количество ресурсов, доступных вашим пользователям.

Вы можете возразить, что это, в принципе, не катастрофа. Конечно, но сервер можно еще перегрузить и сделать его недоступным. Или заставить MySQL использовать всю доступную память, в результате чего сервер будет просто убит операционной системой. На 32-битных системах провести подобные трюки гораздо легче.

Дам вам несколько советов:

* Временные таблицы вы можете использовать запросы с производными таблицами и создавать в памяти неограниченное количество временных таблиц с неограниченным размером.

* Таблицы в памяти Если вы можете создать в памяти одну таблицу, значит вы можете создать любое количество. Хотя размер таблицы ограничен директивой max_heap_table_size, общий размер таблиц не ограничен никак. Вы можете создавать таблицы как TEMPORARY и их не будет в файловой системе.

* MyISAM Sort Buffer - обычно его размер устанавливают довольно большим, но он может одноврменно работать только с несколькими таблицами. А что будет, если пользователь использует все его дозволеные 100 подключений для инструкции ALTER для 100 разных таблиц? Можно искусственно ограничить его занижением значения параметра myisam_sort_buffer_size, но это отразится на производительности.

* Количество подготовленных инструкций (Prepared Statements) - к счастью теперь есть лимит на максимальное количество подготовленных инструкций (параметр max_stmt_count), который задается сервером. Это лучше, чем было раньше, когда можно было заставить сервер использовать всю доступную память, просто забыв закрыть полготовленные инструкции. Однако ограничения для пользователя отстутствуют и один пользователь может исчерпать весь лимит, заблокировав досутп к использованию подготовленных инструкций для остальных. Кроме того, не все инструкции занимают одинаковое количество памяти и подготовка сложных инструкций может отнять бoльшую часть ресурсов. Решить проблему можно, ограничив использование подготовленных инструкций и установив параметр max_prepared_stmt_count в очень низкое значение.

* Подготовленные инструкции и BLOB-данные - если вы хотите получить память, занятую одной подготовленной инструкцией, вы можете создать инструкцию с тысячей меток (placeholders) и посылать данные каждой из них, используя вызов mysql_stmt_send_long_data. Буферы сервера будут принимать данные до тех пор, пока инструкция не будет выполнена.

* Утечки кэша таблиц Innodb - InnoDB никогда не ограничивает размер внутренних таблиц в кеше (словарь данных). Так что открывая большие таблицы и работая с ними вы можете исчерпать всю доступную память. ОБычно размер 4-8К на таблицу, но сложные таблицы могут занимать и больше. В основном это проблема небольших серверов.

* Кэш Слитых таблиц - кэш таблиц обычно распределен и каждая запись обычно соответствует не более, чем паре файловых дескрипторов. Но не в случае Слитых таблиц - создание и доступ к нескольким слитым таблицам с, например, тысячей подтаблиц не лучшим образом скажется на вашем сервере. Тоже самое относится и к Разделенным талицам из MySQL 5.1 Место на диске - для MyISAM-таблиц хостинг-провайдеры обычно используют дисковые квоты. Вы можете использовать похожий подход при помощи innodb_file_per_table. Однако вы не можете контролировать рост системных таблиц InnoDB, которые используются для хранения данных об отменах и которые могут увеличиваться с каждой открытой транзакцией и делать множество обновлений. Или просто сохранять транзакцию открытой и позволять другим пользователям делать обновления - InnoDB может только очистить данные после старых транзакций, нуждающихся в мгновенном коммите. Вы можете решить этот вопрос путем уничтожения слишком старых транзакций, но более верным решением будет установление некоего лимита на объем хранимой информации о отменах. Еще один неплохой способ - это использовать запросы с большими временными таблицами или сортировкой файлов. Даже если временные таблицы будут храниться на другом разделе, при его переполнении другие пользователи не смогут нормально работать с сервером.

* Хранимые процедуры - сколько памяти можно выделить для хранимой процедуры? Можно создать 1000 переменных в хранимой процедуре и зарезервировать для каждой их них по 1М памяти. Я не проводил целенаправленных экспериментов, но думаю, что жесткой политики выделения памяти для хранимых процедур нет.

* Указатели в хранимых процедурах - указатели в хранимых процедурах реализованы в виде временных таблиц. Поэтому используя большое количество указателей можно заполнить доступный объем оперативной памяти.

* Рекурсия в хранимых процедурах - На самом деле отличается от "классического" представления рекурсии. Это всего лишь вызовы одной процедуры из другой. Которые так же требуют выделения памяти и, что важно, размещаются в стеке. Есть некоторые способы для защиты от переполнения стека, но они не могут гарантировать 100%-ного результата.

* Переменные на стороне сервера - каждый сервер имеет ограничение в виде директивы max_allowed_packet (1M по умолчанию). Но, по-видимому, нет никаких ограничений на количество создаваемых перменных.

* Разбор деревьев - внутренне представление запросов в MySQL выглядит как разбор дерева, которое зависит от размера запроса, который, в свою очередь, контролируется директивой max_allowed_packet. Но некоторые способы оптимизирования MySQL (такие как equity propagation и range expansion) могут привести к критическим ошибкам при анализе дерева. Для нескольких тривиальных случаев такое поведение было исправлено, но вызывает сомнения, что эти исправления актуальны для всех подобных ситуаций.

* Сессионные переменные - нет никаких ограничений на использование переменных непривилегированным пользователем, которому разрешено выполнять запросы без ограничения доступа к ресурсам.

* Блокировка хоста - сервер может заблокировать хост клиента из-за большого количества неудачных соединений. Этого можно избежать, выставив большое значение для параметра max_connect_errors, но будьте осторожны: это снизит устойчивость к брутфорсу.

* Взаимные исключения - как InnoDB, так и MyISAM имеют "хотспоты" с несколькими соединениями. Используя их можно существенно замедлить работу сервера. Перегрузка - у MySQL нет достаточного контроля за использованием ресурсов и вы можете "положить" сервер просто выполняя тяжелые запросы. Существующие ограничения не могут полностью контролировать потребление ресурсов пользователем, поскольку не имеют механизма определения "тяжести" запроса. Тяжелые запросы могут сильно нагрузить систему ввода/вывода и заполнить кэш ОС, что заметно снизит скорость работы сервера и запросы других пользователей будут выполняться на порядок медленнее.

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

Как вы видите, MySQL-сервер отнюдь не выглядит "пуленепробиваемым", если кто-то намеренно будет пытаться его обрушить. Дело в том, что большинство существующих ограничений (таких как max_heap_table_size или max_prepared_stmt_count) реализованы для защиты от типичных ошибок при разработке приложений, а отнюдб не от запланированной атаки.

Примечание: я рассмотрел лишь некоторые из объектов сервера, т.е. снижение производительности при некорректной работе с каждым из них. Существует ряд глобальных квот, которые влияют на работу сервера в целом - вы не можете применить их для конкретного пользователя или соединения.

P.S.: вы можете подумать: "как же это все возможно, если существуют тысячи хостинг-провайдеров, предоставляющих доступ к своим серверам БД?" Да, некоторым везт и их пользователи не создают проблем для корректной работы MySQL, но большинству приходится "вручную" постоянно контролировать и ограничивать пользователей, мешающих нормальному функционированию. Не говоря о компаниях, предоставляющих вирутальный хостинг - там, как правило, используются старые версии ПО, имеющие куда больше проблем.

P.P.S.: ничего из вышеописанного не является "новостью" для команды разработчиков MySQL. Эта заметка - лишь попытка осветить некоторые аспекты безопасности и обеспечения корректной работы MySQL-сервера.

Re: 10+ способов обрушить mysql-сервер

Добавлено: 03 янв 2011, 10:40
Hitsugaya Toushirou
*YES*

Re: 10+ способов обрушить mysql-сервер

Добавлено: 15 авг 2016, 15:00
66613
*COOL*