4.2.9 Управление доступом, этап 1: верификация подсоединения
При попытке соединения с сервером MySQL он либо устанавливает соединение,
либо отказывает в нем - на основе данных о вашей личности и того, можете
ли вы подтвердить их соответствующим паролем. Если нет, сервер полностью
отказывает вам в доступе. В противном случае сервер устанавливает
соединение, затем переходит ко второму этапу и ожидает запросов.
Личность задается двумя порциями информации:
-
хостом, с которого вы подсоединяетесь
-
вашим именем пользователя MySQL
Проверка личности осуществляется с помощью трех полей контекста таблицы
user
(Host
, User
и Password
). Сервер устанавливает соединение только в том
случае, если находит в таблице user
запись, в которой имя хоста и имя
пользователя совпадают с введенными вами, и вы указываете правильный
пароль.
Значения в полях контекста таблицы user
могут задаваться следующим
образом:
Непустые значения в поле Password
представляют собой зашифрованные пароли.
В MySQL пароли не хранятся в виде открытого текста, который может
прочитать кто угодно. Напротив, пароль, который вводится пользователем при
попытке подсоединения, шифруется (с помощью функции PASSWORD()
). В
дальнейшем зашифрованный пароль используется клиентом/сервером в процессе
проверки его правильности (это делается вообще без пересылки пароля во
время подсоединения). Заметим, что с MySQL считает зашифрованный пароль
РЕАЛЬНЫМ паролем, поэтому не следует допускать к нему кого бы то ни было!
В частности, не разрешайте обычным пользователям доступ для чтения к
таблицам в базе mysql
!
Примеры, приведенные ниже, показывают, каким входящим подсоединениям
соответствуют различные комбинации значений, указанных в полях Host
и User
таблицы user
:
Значение в поле Host | Значение в поле User | Подсоединения, которым соответствует запись
|
'thomas.loc.gov' | 'fred' | fred , подключающийся с thomas.loc.gov
|
'thomas.loc.gov' | '' | Любой пользователь, подключающийся с thomas.loc.gov
|
'%' | 'fred' | fred , подключающийся с любого хоста
|
'%' | '' | Любой пользователь, подключающийся с любого хоста
|
'%.loc.gov' | 'fred' | fred , подключающийся с любого хоста, принадлежащего домену loc.gov
|
'x.y.%' | 'fred' | fred , подключающийся с x.y.net , x.y.com ,x.y.edu , и т.д. (это, по-видимому, бесполезный вариант)
|
'144.155.166.177' | 'fred' | fred , подключающийся с хоста, имеющего IP-адрес 144.155.166.177
|
'144.155.166.%' | 'fred' | fred , подключающийся с любого хоста в подсети 144.155.166 класса C
|
'144.155.166.0/255.255.255.0' | 'fred' | То же самое, что и в предыдущем примере
|
Поскольку в IP-адресе, указываемом в поле Host
, могут использоваться
шаблонные символы (например '144.155.166.%'
- данное значение
соответствует всем без исключения хостам указанной подсети), возникает
опасность, что кто-нибудь может попытаться воспользоваться этой
возможностью, указав имя хоста, например, как 144.155.166.somewhere.com
.
Чтобы ``поставить заслон'' таким попыткам, в MySQL не разрешены имена
хостов, начинающиеся с цифр и точки. Другими словами, имени хоста типа
1.2.foo.com
, никогда не найдется соответствия в столбцах Host
таблиц
привилегий. IP-адресу с шаблонными символами может соответствовать только
IP-адрес.
Входящее подсоединение может совпадать с несколькими записями в таблице
user. Например, как было показано выше, подсоединению с thomas.loc.gov by
fred
могут подходить разные записи. Каким образом сервер определяет, какую
из записей использовать, при совпадении с более чем одной из них? Для
этого после считывания таблицы user
во время запуска сервер производит ее
сортировку, а затем, когда пользователь пытается установить соединение,
записи таблицы просматриваются в порядке их упорядочения,. Используется
первая подошедшая запись.
Сортировка таблицы user осуществляется следующим образом. Предположим,
таблица user
имеет следующий вид:
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| % | root | ...
| % | jeffrey | ...
| localhost | root | ...
| localhost | | ...
+-----------+----------+-
При считывании этой таблицы сервер упорядочивает записи, начиная с
наиболее конкретных значений в столбце Host
('%'
в столбце Host
означает
``любой хост'' и является наименее конкретным). Записи с одинаковым
значением в столбце Host
упорядочиваются между собой начиная с наиболее
конкретных значений в столбце User
(пустое значение в столбце User
означает ``любой пользователь'' и является наименее конкретным).
Окончательно отсортированная таблица user
имеет следующий вид:
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| localhost | root | ...
| localhost | | ...
| % | jeffrey | ...
| % | root | ...
+-----------+----------+-
При попытке подсоединения сервер просматривает отсортированные записи и
использует первую подходящую запись. Для подсоединения с localhost
пользователя jeffrey
первыми подходящими записями являются записи со
значением 'localhost'
в столбце Host
. Из них запись с пустым значением
имени пользователя соответствует и имени подсоединяющегося хоста и имени
пользователя. (запись '%'/'jeffrey'
тоже подошла бы, но она -- не первая
подходящая в этой таблице).
Рассмотрим другой пример. Пусть таблица user
имеет вид:
+----------------+----------+-
| Host | User | ...
+----------------+----------+-
| % | jeffrey | ...
| thomas.loc.gov | | ...
+----------------+----------+-
Отсортированная таблица выглядит следующим образом:
+----------------+----------+-
| Host | User | ...
+----------------+----------+-
| thomas.loc.gov | | ...
| % | jeffrey | ...
+----------------+----------+-
Для подсоединения пользователя jeffrey
с thomas.loc.gov
подходит первая
запись, в то время как для подсоединения jeffrey
с whitehouse.gov
-
вторая.
Существует распространенное заблуждение: иногда думают, что при поиске
записей для данного имени пользователя, соответствующих определенному
подсоединению, сервер первыми будет использовать записи, в которых этот
пользователь указан явно. Это абсолютно неверно, как и продемонстрировано
в предыдущем примере: для подсоединения пользователя jeffrey
с
thomas.loc.gov
первой подходящей записью является не запись, содержащая
значение 'jeffrey'
в поле User
, а запись, не содержащая имени пользователя
вовсе!
Если у вас возникают проблемы с подсоединением к серверу, распечатайте
таблицу user
и отсортируйте ее вручную, чтобы увидеть, где
происходит первое совпадение.