O objetivo principal deste artigo é descrever os mecanismos de controles de acessos do MySQL, bem como apresentar as rotinas para criação de usuários e gerenciamento de seus privilégios.
O MySQL possui um mecanismo que permite limitar o acesso de um usuário a apenas um banco, tabela ou coluna, além de poder controlar o acesso de acordo com o host a partir de onde está sendo feita a conexão com o servidor. Pode-se ainda, conceder privilégios diferentes para cada host de onde o usuário possa estabelecer a conexão. Assim, é possível que determinados comandos possam ser executados somente quando o usuário estiver em um host específico, por exemplo o mesmo host do servidor MySQL (localhost).
O MySQL armazena as informações dos seus usuários em 4 tabelas que estão localizadas no banco de dados mysql. Estas tabelas são a user, db, tables_priv e columns_priv. A tabela user armazena as informações de todos os usuários do banco e os privilégios globais deste usuário. A tabela db armazena os privilégios dos usuários específicos de um banco de dados. Finalmente, as tabelas tables_priv e columns_priv armazenam os privilégios associados a tabelas e colunas, respectivamente. Como estas tabelas possuem as informações dos usuários, bem como os seus privilégios, recomenda-se que apenas o administrador do banco de dados tenha acesso ao banco mysql (usuário root).
Para criar usuários e conceder privilégios no MySQL, utiliza-se o comando GRANT. Ao executar um comando GRANT para um usuário que não existe, o mesmo será criado. Um GRANT para um usuário já existente adicionará os novos privilégios aos já concedidos anteriormente. A sintáxe resumida do comando GRANT é exibida a seguir:
GRANT priv [(colunas)] [, priv [(colunas)]] ...
ON {*.* | db.* | db.tabela}
TO usuario [IDENTIFIED BY 'senha']
[, usuario [IDENTIFIED BY 'senha']] ...
[WITH [GRANT OPTION |
MAX_QUERIES_PER_HOUR contador |
MAX_UPDATES_PER_HOUR contador |
MAX_CONNECTIONS_PER_HOUR contador]]
No comando acima os [ ] indicam que o comando é opcional. O primeiro item a ser informado é(são) o(s) privilégio(s) a ser(em) concedido(s) ao(s) usuário(s). A lista de privilégios existentes no MySQL é descrita abaixo:
Privilégio | Descrição |
---|---|
ALL [PRIVILEGES] | Todos os privilégios exceto GRANT OPTION |
ALTER | Permite executar ALTER TABLE |
CREATE | Permite executar CREATE TABLE |
CREATE TEMPORARY TABLES | Permite executar CREATE TEMPORARY TABLE |
DELETE | Permite executar DELETE |
DROP | Permite executar DROP TABLE |
EXECUTE | Permite executar stored procedures (MySQL 5.0) |
FILE | Permite executar SELECT ... INTO OUTFILE e LOAD DATA INFILE |
INDEX | Permite executar CREATE INDEX e DROP INDEX |
INSERT | Permite executar INSERT |
LOCK TABLES | Permite executar LOCK TABLES em tabelas que você tenha o privilégio SELECT |
PROCESS | Permite executar SHOW FULL PROCESSLIST |
REFERENCES | Ainda não está implementado |
RELOAD | Permite executar FLUSH |
REPLICATION CLIENT | Permite ao usuário obter a localização do Master ou Slave |
REPLICATION SLAVE | Necessário para a replicação Slave (leitura dos eventos do log binário do Master) |
SELECT | Permite executar SELECT |
SHOW DATABASES | exibe todos os bancos de dados |
SHUTDOWN | Permite executar mysqladmin shutdown |
SUPER | Permite executar CHANGE MASTER, KILL , PURGE MASTER LOGS e SET GLOBAL. Permite conectar-se ao servidor uma vez, mesmo que o max_connections tenha sido atingido |
UPDATE | Permite executar UPDATE |
USAGE | Sinônimo para "no privileges'' |
GRANT OPTION | Permite ao usuário repassar os seus privilégios |
Uma vez informados os privilégios do usuário, você deverá indicar o nível ao qual o privilégio se aplica, sendo possível especificar três níveis:
*.* | Privilégio global |
db.* | Qualquer tabela do banco db |
db.tb | Apenas a tabela tb do banco de dados db. Para especificar apenas algumas colunas de uma determinada tabela, estas deverão ser listadas ao lado do privilégio (priv (colunas)) |
Depois do nível você deverá indicar o usuário, ou a lista de usuários, para os quais os privilégios se aplicam. No MySQL o usuário é constituído de um nome mais o host de onde ele poderá acessar o servidor (user@host). Caso você não informe o host para o usuário, o MySQL assumirá "%", isto é, todos os hosts. A senha do usuário é opcional, mas é recomendado sempre informá-la no momento de criação do usuário, por questões de segurança. Para adicionar privilégios a um usuário existente o IDENTIFIED BY poderá ser omitido. No exemplo a seguir é criado um usuário com o nome teste que pode se conectar somente do host onde o servidor está em execução (localhost), o usuário só poderá fazer SELECT nas colunas nome e idade da tabela pessoa, que se encontra no banco de dados rh. A senha do usuário é 12345.
GRANT SELECT (nome, idade) ON rh.pessoa TO teste@localhost
IDENTIFIED BY "12345";
Para listar os privilégios deste usuário utilize o comando:
SHOW GRANTS FOR teste@localhost;
Você pode especificar um conjunto de hosts utilizando o caracter "%", neste caso é possível dar acesso a um usuário dentro de uma faixa de IPs ou DNS. Usuários anônimos também podem ser criados informando um nome com o caracter espaço (" "). No exemplo a seguir, o usuário remoto poderá executar UPDATE e INSERT em qualquer tabela do banco de dados rh, sendo possível a conexão ao servidor a partir de qualquer máquina no domínio mysqlbrasil.com.br:
GRANT UPDATE, INSERT ON rh.* TO remoto@"%.mysqlbrasil.com.br"
IDENTIFIED BY "remoto";
Ou utilizando IP:
GRANT UPDATE, INSERT ON rh.* TO remoto@"200.236.13.%" IDENTIFIED BY "remoto";
Um usuário anônimo com os mesmos privilégios do usuário remoto seria criado da seguinte forma:
GRANT UPDATE, INSERT ON rh.* TO " "@"%mysqlbrasil.com.br"
IDENTIFIED BY "anonimo";
Finalmente, a opção GRANT OPTION é utilizada para que o usuário possa conceder os seus privilégios para outros usuários do banco. Além disto, você poderá limitar os recursos do usuário com as opções MAX_QUERIES_PER_HOUR, MAX_UPDATES_PER_HOUR ou MAX_CONNECTIONS_PER_HOUR.
Para remover um privilégio do usuário utilize o comando REVOKE mostrado abaixo:
REVOKE priv [(colunas)] [, priv [(colunas)]] ...
ON {*.* | db.* | db.tabela}
FROM usuario [, usuario] ...
Lembre-se de que a parte ON do REVOKE deverá coincidir com a parte ON do GRANT que você deseja remover, caso isto não se verifique o comando REVOKE não terá efeito algum. Além disto, o comando REVOKE remove apenas os privilégios do usuário, mas o usuário continuará existindo. A remoção do usuário deverá ser feita com um DELETE explícito na tabela de usuários do MySQL, após terem sido Removidos todos os seus privilégios com o comando REVOKE. Observe que para remover o usuário você deverá ter privilégio para executar DELETE na tabela user do mysql. Geralmente, esta tarefa é executada pelo administrador do banco (root).
DELETE FROM mysql.user WHERE user="teste" AND host="localhost";
Feito isto, você terá que executar um comando FLUSH PRIVILEGES para que o MySQL possa atualizar os privilégios que estão em memória.
FLUSH PRIVILEGES;
Aqui estamos descrevendo os comandos para a manipulação de usuários, sendo que esta é a maneira de entendermos como funciona a criação de usuários no MySQL. Uma forma mais intuitiva para executar esta tarefa pode ser encontrada no MySQL Administrator, que foi apresentado no último artigo.
Problemas para a conexão com o MySQL a partir do localhost
Ao instalar o MySQL são criados o usuário root com todos os privilégios (administrador), podendo se conectar somente do host local sem senha, e o usuário anônimo com privilégios apenas no banco de dados test, que pode se conectar apenas do host local sem senha. Para autentiticar um usuário durante a conexão com o servidor, o MySQL armazena em memória a listas de todos usuários, hosts e senhas cadastrados no banco e as ordena do host mais específico para o menos específico. Caso existam dois hosts iguais, os usuários mais específicos virão antes do usuário anônimo. Feito isto, a cada conexão será pesquisada nesta lista a primeira ocorrência que coincida o host, usuário e senha informados no momento da tentativa de conexão. Tomemos o caso em que após a instalação do MySQL, criamos um usuário que possa se conectar a partir de qualquer host dentro do domínio onde se encontra o servidor MySQL:
GRANT ALL ON rh.* TO user@"192.168.0.%" IDENTIFIED BY "12345";
Neste caso, o MySQL cria em memória a lista dos usuários da seguinte forma:
Usuário Senha
root@localhost
" "@localhost
user@"192.168.0.%" 12345
Este usuário será capaz de se conectar ao servidor MySQL a partir de qualquer máquina no domínio, exceto o host local, pois neste caso, ao pesquisar na lista pelo user@localhost, a primeira ocorrência encontrada é a do usuário anônimo, já que qualquer usuário pode ser considerado anônimo pelo MySQL. O detalhe é que as senhas destes usuários não coincidem, o que gera um erro de "Acesso Negado". Para evitar a situação acima você deverá excluir o usuário anônimo ou adicionar o mesmo usuário para se conectar remoto e a partir do host local, da seguinte forma:
GRANT ALL ON rh.* TO user@"192.168.0.%" IDENTIFIED BY "12345",
user@localhost IDENTIFIED BY "12345";
Assim a ordenação ficaria:
Usuário Senha
root@localhost
user@localhost 12345
" "@localhost
user@"192.168.0.%" 12345
Desta forma, o primeiro registro encontrado não é mais o usuário anônimo e sim o user@localhost, portanto a conexão será estabelecida com sucesso. Para evitar este tipo de transtorno é melhor remover o usuário anônimo após a instalação do servidor, eliminando também eventuais problemas de segurança.