Люди часто спрашивают об ошибках, подобных этой - http://bugs.mysql.com/bug.php?id=32125. Такие ошибки дают простую возможность обвалить работу MySQL любому пользователю с базовыми правами.
В этом нет ничего нового, можно сесть на место и расслабиться. На самом деле, существует множество способов вывести сервер любой версии MySQL из строя, достаточно только иметь к нему доступ с базовыми правами. Мы постоянно помогаем людям поправлять ошибки в приложениях, которые делают MySQL бесполезным (несколько из них приводят к краху, если говорить честно) , ведь это может быть сделано очень легко, особенно если иметь такое намерение.
По моему мнению, безопасность MySQL необходимо рассматривать с такой позиции – если вы не предоставляете доступа к серверу MySQL – вы точно вне опасности. Известны атаки на серверы СУБД, с которыми MySQL справляется легко, если у атакующего нет учетной записи для доступа к серверу. Но как только наступает момент – вы выдаете кому-то логин и пароль, то вся система безопасности гарантирует, что этот пользователь не увидит чужих данных, но отсутствуют гарантии, что не будет нанесен ущерб работе сервера в целом. Эту ситуацию будет невозможно изменить до тех пор, пока в MySQL не будет реализовано Глобальное Управление Ресурсами (GRM, Global Resource Management) так как иначе нельзя контролировать количество ресурсов, выделяемых пользователю. Вы можете сказать, что жор ресурсов это еще не падение. Теоретически верно, но подобный катаклизм приводит к недоступности сервера, что зачастую вызывает перенагрузку MySQL и он начинает требовать от системы так много памяти, что выходит за допустимые рамки и процесс убивается. В 32-битных системах этого добиться даже еще легче, ведь MySQL перестанет работать как только один из процессов распределения внутренней памяти неожиданно даст сбой.
Временные таблицы.
Вы можете построить запрос с использованием как можно большего количества временных таблиц с максимально возможным для вас размером. Таблицы будут созданы в памяти. Если вы имеете возможность создавать таблицы памяти, то вы можете создать их сколько угодно, даже каждой таблицы будет не лимитированным. Заметьте, что вы можете создать эти таблицы как ВРЕМЕННЫЕ и тогда их будет не так-то легко найти в файловой системе.
Буфер сортировки MyISAM.
Не смотря на то, что параметр max_heap_table_size, ограничивающий размер Не произойдет ничего страшного, если структура только пары таблиц одновременно меняется. Но что будет, если пользователь задействует все допустимые для него 100 подключений, чтобы выполнить ALTER для 100 разных таблиц? Конечно, параметр myisam_sort_buffer_size не даст проблеме разрастись, но производительность пострадает.
Количество Подготовленных Выражений.
К счастью, теперь существует лимит общего числа подготовленных выражений (max_prepared_stmt_count) который влияет на сервер. Поэтому дела обстоят гораздо лучше, чем было раньше, когда приложение, забывшее закрыть подготовленное выражение могло привести к «поеданию» памяти сервером. Правда, в итоге так и не появилось ограничений для каждого пользователя, соответственно любой пользователь может использовать лимит «в одно лицо» в ущерб остальным пользователям. Более того, все подготовленные выражения требуют разного количества памяти и создавая сложные выражения вы можете «съесть» большое количество памяти.
Вывод по этой проблеме – старайтесь избегать подготовленных выражений и устанавливайте маленькие значения для параметра max_prepared_stmt_count.
Подготовленные выражения и данные BLOB.
Если вы хотите съесть всю память одним подготовленным выражением, то создайте в выражении тысячи меток-плейсхолдеров и отправьте данные для каждой из них используя mysql_stmt_send_long_data call – сервер буферизует данные до тех пор, пока все выражение не будет выполнено.
Утечка таблицы кэша InnoDB.
InnoDB никогда не урезает свою внутреннюю таблицу кэша (словаря данных), поэтому, создавая и обращаясь к большому количеству таблиц InnoDB вы можете затребовать большое количество памяти сервера. Размер таблицы средней сложности составляет обычно 4-8К, поэтому это проблема в основном небольших серверов.
Табличный кэш Merge.
Кэш таблиц обычно не использует более пары дескрипторов файлов, но это не в случае с таблицами Merge. Создание и осуществление доступа к нескольким объединенным таблицам Merge, включающим в себя 1000 подтаблиц, приведет к проблеме с файловыми дескрипторами. Это действительно и для разделенных (partitioned) таблиц в MySQL 5.1.
Дисковое пространство для MyISAM.
Хостинг-провайдеры обычно используют дисковые квоты для таблиц MyISAM. Вы можете использовать ту же технику, что и с innodb_file_per_table. Но не смотря на это, вы не можете контролировать рост размера таблицы при открытии транзакции и выполнении множественных обновлений данных, или простого открытия транзакции и предоставления другим пользователям права выполнять обновления. InnoDB очищает данные только после того, как найстарейшая транзакция потребует коммита. Вы можете выполнить обходной маневр для данной уязвимости, убивая транзакции, которые уже очень стары.
Еще один способ создать трудность – использовать запросы с использованием больших временных таблиц или сортировки, которая может поглотить все пространство. Даже если они расположены в другом разделе (partition), вы получите ситуацию когда остальные пользователи не смогут выполнять своих запросов. Хранимые процедуры. Сколько памяти может потребовать хранимая процедура? Скажем, вы создаете 1000 переменных внутри процедуры и устанавливаете 1М значений для каждой из них. Я не экспериментировал с другими конструкциями языка хранимых процедур, но я полагаю, что здесь нет строгой политики выделения памяти.
Курсоры хранимых процедур.
Курсоры внутри хранимых процедур выполнены в виде временных таблиц, поэтому, открывая большое количество курсоров, вы можете «съесть» много памяти.
Рекурсия хранимых процедур.
Если быть точным, то я имею ввиду не совсем чистую рекурсию, а говорю о двух различных хранимых процедурах, где одна вызывает другую. Стек вызовов переполняется и может затребовать много памяти. Существуют некоторые инструменты защиты от выхода за пределы стека, но они охватывают не все ситуации. Переменные на стороне сервера. Каждая переменная на серверной стороне может хранить значение доходящее до максимальной величины, которая ограничена параметром max_allowed_packet (1 М по умолчанию), но что-то я не припомню ограничений на количество самих переменных для каждого пользователя/процесса.
Парсинг дерева.
Запрос внутри MySQL представлен в виде дерева, которое, конечно, зависит от размера запроса (размер контролируется параметром max_allowed_packet), но некоторые действия по оптимизации могут приводить к раздуванию дерева в размерах. Для большинства случаев эта проблема пофиксена, но я не уверен что для всех.
Переменные сессии.
Не существует ограничений на размер, который вы можете установить для переменных соединения непривилегированного пользователя, который позволяет выполнять запросы с неконтролируемым использованием ресурсов.
Блокирование хоста.
Вы можете заблокировать свой хост для обслуживания сервером, симулируя количество неудачных подключений. Конечно, можно установить большое число в параметре having high max_connect_errors, но тогда вы станете более уязвимыми для брутфорс-атак (метод перебора паролей).
Флаги насыщения.
Как InnoDB, так и MyISAM имеют точки максимального использования в памяти. Создавая несколько параллельных соединений, которые одновременно выполняют одинаковые операции, вы урезаете производительность системы. Общая перенагрузка. Так как MySQL не осуществляет особого контроля использования ресурсов, вы можете просто-напросто использовать «тяжелые» запросы, чтобы ограничить производительность. Существующие ограничения не всегда реально спасают ситуацию, так как не ориентированы прежде всего на конкретного пользователя, а на систему в целом. «Тяжелые» запросы на запись/считывание с диска могут быть наихудшими для производительности, так как перенагружают и систему ввода/вывода и отрицательно влияют на кэш как MySQL так и операционной системы. Кое что из вышесказанного было получено из личного опыта, а еще кое что – мои догадки и соображения. Как мы можем видеть, большинство ограничений в MySQL, такие как max_heap_table_size или max_prepared_stmt_count призвано спасти сервер от общих ошибок работы приложений, но не от злого умысла пользователей сервера баз данных.
PS: Я исследовал только некоторые серверные объекты, чтобы в целом убедиться, что в MySQL существуют глобальные ограничения на использование памяти, но не контроль за выделением ресурсов каждому пользователю.
Вы можете спросить – как это может быть правдой, если тысячи компаний оказывают услуги виртуального хостинга с доступом к общей MySQL. Да, это действительно так, но их пользователи работают с MySQL поверхностно и не пытаются «завалить» систему специально. Почти все хостинг компании вынуждены постоянно искать и ограничивать пользователей, требующих большое количество ресурсов. По стоимости на услуги виртуального хостинга в той или иной компании можно определить на сколько разбит физический сервер, следовательно сколько пользователей грузят общий MySQL. Чем меньше пользователей тем сервер более стабильней но в свою очередь дороже.
PPS: Ничего из того что я описал выше, не является дырой в безопасности и все это известно компании MySQL. Все, чего я пытаюсь добиться – пояснить, что проблемы существуют и это не связано с безопасностью в MySQL.