Распределение прав доступа

Аутентификация пользователя производится по имени (до 16 символов), паролю (м.б. пустым) и хосту или его IP. Большинство клиентских программ по умолчанию используют mysql-имя, совпадающее с unix-именем, но это можно изменить с помощью ключа --user=. Пароль можно задать:
  • прямо в командной строке после ключа -p (без пробела, очень опасно)
  • указав ключ -p без пароля (программа запросит пароль с клавиатуры, наиболее безопасно)
  • в файле .my.cnf (права к этому файлу должны быть только у собственника), секция [client], поля host, user и password
  • с помощью переменной окружения MYSQL_PWD (очень опасно) и MYSQL_HOST

Вся информация о правах хранится в БД с именем mysql. Никто не должен иметь к ней доступа на чтение (см. про пароли).

Используются таблицы:

  • user (используется чтобы понять - пускать/не пускать; данные здесь права действуют на все БД; административные привилегии и операции с файлами определяются только здесь)
    • Host: CHAR(60),PRI, нечувствителен к регистру. Может содержать имя хоста, IP адрес или localhost. Можно использовать шаблоны с символами '%' (любое количество любых символов) и '_' (любой символ). Пустое поле означает, что производится логическое "И" привилегий в данной строке и привилегий в соответствующей строке таблицы host. При использовании IP-адреса можно задавать сетевую маску (в виде - /255.255.255.0 или /24).
    • User: CHAR(16),PRI. Пустое поле соответствует любому имени, в данном случае пользователь рассматривается как анонимный и предоставленное им имя заменяется на пустое для дальнейших проверок прав доступа.
    • Password: CHAR(16), зашифрован, но не так как в Unix, знание даже зашифрованного пароля позволяет выдать себя за данного пользователя - пароль шифруется на стороне клиента! Может быть пустым - пользователь также должен предъявить пустой пароль.
    • привилегии: enum('N','Y'), по умолчанию - 'N'
      • select - выборка из строк таблицы
      • insert - вставка строки в таблицу
      • update - изменение строки таблицы
      • delete - удаление строки таблицы
      • create - создавать БД/таблицу
      • drop - удалять БД/таблицу
      • reload - позволяет выполнять административные команды (reload, refresh, flush-*)
      • shutdown - позволяет остановить mysqld
      • process - позволяет выполнить processlist (можно смотреть текст команд, выполняемых другими пользователями (в т.ч. SET PASSWORD)), kill
      • file - читать файлы (LOAD DATA INFILE) и писать файлы (SELECT ... INTO OUTFILE), с точки зрения Unix используются права, с которыми запущен mysqld (в частности, он может прочитать /etc/passwd, любую БД и т.п., записать файл в /tmp и т.п., но не может переписать уже существующий файл)
      • grant - передавать свои привилегии другим, два пользователя с различными привилегиями могут объединить их ;)
      • index - создавать/удалять индексы таблицы
      • alter - изменять формат таблицы, в том числе переименовать ее, что позволяет обмануть систему прав доступа
  • host
    • Host: CHAR(60),PRI. '%' или пустое поле означает - любой хост.
    • DB: CHAR(64),PRI. '%' или пустое поле означает - любая БД.
    • привилегии: enum('N','Y'), по умолчанию - 'N'
      • select
      • insert
      • update
      • delete
      • create
      • drop
      • grant
      • references
      • index
      • alter
  • db
    • Host: CHAR(60),PRI. Строка '%' означает - при доступе с любого хоста. Пустое поле означает необходимость посмотреть в таблицу host.
    • DB: CHAR(64),PRI. '%' или пустое поле означает - любая БД.
    • User: CHAR(16),PRI. Пустое поле - анонимный пользователь.
    • привилегии: enum('N','Y'), по умолчанию - 'N'
      • select
      • insert
      • update
      • delete
      • create
      • drop
      • grant
      • references
      • index
      • alter
  • tables_priv
    • Host: CHAR(60),PRI. '%' или пустое поле означает - любой хост.
    • DB: CHAR(60),PRI. Не м.б. пустым или содержать шаблоны.
    • User: CHAR(16),PRI. Пустое поле - анонимный пользователь.
    • Table_name: CHAR(60),PRI. Не м.б. пустым или содержать шаблоны.
    • Grantor: CHAR(77)
    • Timestamp: timestamp(14)
    • Table_priv: set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter')
    • Column_priv: set('Select','Insert','Update','References')
  • culumns_priv
    • Host: CHAR(60),PRI. '%' или пустое поле означает - любой хост.
    • DB: CHAR(60),PRI. Не м.б. пустым или содержать шаблоны.
    • User: CHAR(16),PRI. Пустое поле - анонимный пользователь.
    • Table_name: CHAR(64),PRI. Не м.б. пустым или содержать шаблоны.
    • Column_name: CHAR(64),PRI. Не м.б. пустым или содержать шаблоны.
    • Timestamp: timestamp(14)
    • Column_priv: set('Select','Insert','Update','References')

Проверка права на подсоединение к серверу: mysql-клиент предъявляет имя пользователя, сервер определяет имя (или IP) хоста клиента (или localhost для обращения через unix-socket). По данной паре (адрес/имя) ищется строка в таблице user. Предварительно таблица сортируется по полям (Host/User) так, что наиболее специфичные строки оказываются первыми, наименее специфичные - последними. Если строка не найдена, то соединение отвергается. Если - найдена, то сверяется пароль.

Проверка прав при исполнении каждого запроса: таблица db сортируется по полям Host, Db и User, таблица host по полям Host и Db, таблицы tables_priv и columns_priv по полям Host, Db и User от наиболее специфичного к наименее. Для административных запросов и доступа к файлам проверяется только таблица user. Для прочих запросов в начале проверяется таблица user - а нет ли у данного пользователя прав доступа на "глобальном" уровне. Если есть - операция разрешается. Если нет, то проверяются права доступа к конкретной БД с конкретного хоста (по пересечению таблиц Db и Host с учетом шаблонов и пустых полей). Если их достаточно, то доступ дается. Если недостаточно, то к объединению "глобальных" прав и прав БД/хост добавляются права, извлеченные из таблиц tables_priv и columns_priv. Если и этого не хватает, то увы...

Права доступа читаются mysqld (и не читаются при "ручном" изменении БД mysql):

  • при запуске
  • при выполнении команд GRANT, REVOKE и SET PASSWORD
  • при выполнении команды FLUSH PRIVILEGES
  • при выполнении mysqladmin flush-privileges/reload

"Глобальные" привилегии и изменения пароля вступают в силу только при следующем соединении. Изменения в доступе к БД - при следующей команде use. Изменения в доступе к таблицам и колонкам - при следующем запросе.

Изменение пароля: set password for имя=password('новый пароль').

GRANT тип-привилегии [(список-столбцов)] [, тип-привилегии [(список-столбцов)] ...] ON { имя-таблицы | * | *.* | имя-БД.* } TO имя-пользователя [ IDENTIFIED BY 'пароль' ] [, имя-пользователя [ IDENTIFIED BY 'пароль ] ... ] WITH GRANT OPTION

REVOKE тип-привилегии [(список-столбцов)] [, тип-привилегии [(список-столбцов)] ...] ON { имя-таблицы | * | *.* | имя-БД.* } FROM имя-пользователя [, имя-пользователя ... ]

Типы привилегий:

  • ALL PRIVILEGES (aka ALL)
  • ALTER
  • CREATE
  • DELETE
  • DROP
  • FILE
  • GRANT OPTION (только для REVOKE)
  • INDEX
  • INSERT
  • PROCESS
  • REFERENCES (не реализовано)
  • RELOAD
  • SELECT
  • SHUTDOWN
  • UPDATE
  • USAGE (никаких - просто место застолбить)

Для столбцов можно задавать только INSERT, SELECT и UPDATE. Для таблиц - INSERT, SELECT, UPDATE, CREATE, DROP, DELETE, GRANT, INDEX, ALTER. Использование "*.*" означает задание глобальных привилегий. Использование "*" означает задание привилегий для текущей БД (если текущей БД нет, то глобальные).

SHOW GRANTS FOR имя@хост;

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