Usando% para host ao criar um usuário MySQL

95

Meu banco de dados MySQL precisa de dois usuários: appuser e suporte.
Um dos desenvolvedores de aplicativos insiste que eu crie quatro contas para esses usuários:

appuser@'%'
appuser@'localhost'
support@'%'
support@'localhost'

Pela minha vida, não consigo descobrir por que ele acha que precisamos disso. Usar o curinga como host não cuidaria do 'localhost'?

Alguma ideia?

(Usando MySQL 5.5 aqui)

Ed Manet
fonte

Respostas:

110

localhosté especial no MySQL, significa uma conexão em um soquete UNIX (ou pipes nomeados no Windows, eu acredito) em oposição a um soquete TCP / IP. Usar %como host não inclui localhost, daí a necessidade de especificá-lo explicitamente.

aleroot
fonte
Em qual versão? No MySQL 5.5.35, "%" também corresponde a localhost.
depois de
4
O "localhost" não se conecta apenas através do soquete local, 127.0.0.1 (que não usa o soquete) não corresponderá a%, mas também ao localhost. Vi isso com uma instalação haproxy hoje.
Phillipp
33

Como @nos apontou nos comentários da resposta atualmente aceita para esta pergunta, a resposta aceita está incorreta.

Sim, HÁ uma diferença entre usar %e localhostpara o host da conta do usuário ao conectar por meio de uma conexão de soquete em vez de uma conexão TCP / IP padrão.

Um valor de host de %não inclui localhostpara sockets e, portanto, deve ser especificado se você deseja se conectar usando esse método.

John Kary
fonte
17

Vamos apenas testar.

Conecte-se como superusuário e, em seguida:

SHOW VARIABLES LIKE "%version%"; 
+-------------------------+------------------------------+ 
| Variable_name           | Value                        | 
+-------------------------+------------------------------+ 
| version                 | 10.0.23-MariaDB-0+deb8u1-log | 

e depois

USE mysql;

Configuração

Crie um usuário foocom senha barpara teste:

CREATE USER foo@'%' IDENTIFIED BY 'bar'; FLUSH PRIVILEGES;

Conectar

Para se conectar ao Unix Domain Socket (ou seja, o I / O pipe que é nomeado pela entrada do sistema de arquivos /var/run/mysqld/mysqld.sockou algo assim), execute-o na linha de comando (use a --protocolopção para ter certeza dupla)

mysql -pbar -ufoo
mysql -pbar -ufoo --protocol=SOCKET

Espera-se que o acima corresponda a "usuário vem de localhost", mas certamente não "usuário vem de 127.0.0.1".

Para se conectar ao servidor de "127.0.0.1" em vez disso, execute-o na linha de comando

mysql -pbar -ufoo --bind-address=127.0.0.1 --protocol=TCP

Se você omitir --protocol=TCP, o mysqlcomando ainda tentará usar o soquete de domínio Unix. Você também pode dizer:

mysql -pbar -ufoo --bind-address=127.0.0.1 --host=127.0.0.1

As duas tentativas de conexão em uma linha:

export MYSQL_PWD=bar; \
mysql -ufoo --protocol=SOCKET --execute="SELECT 1"; \
mysql -ufoo --bind-address=127.0.0.1 --host=127.0.0.1 --execute="SELECT 1"

(a senha é definida no ambiente para que seja passada para o mysqlprocesso)

Verificação em caso de dúvida

Para realmente verificar se a conexão passa por um soquete TCP / IP ou um soquete de domínio Unix

  1. obter o PID do processo do cliente mysql examinando a saída de ps faux
  2. correr lsof -n -p<yourpid>.

Você verá algo como:

mysql [PID] quux 3u IPv4 [code] 0t0 TCP 127.0.0.1:[port]->127.0.0.1:mysql (ESTABLISHED)

ou

mysql [PID] quux 3u unix [code] 0t0 [code] socket

Então:

Caso 0: Host = '10 .10.10.10 '(teste nulo)

update user set host='10.10.10.10' where user='foo'; flush privileges;
  • Conecte usando o soquete: FAILURE
  • Conectar de 127.0.0.1: FALHA

Caso 1: Host = '%'

update user set host='%' where user='foo'; flush privileges;
  • Conecte usando o soquete: OK
  • Conectar de 127.0.0.1: OK

Caso 2: Host = 'localhost'

update user set host='localhost' where user='foo';flush privileges;

O comportamento varia e isso aparentemente depende skip-name-resolve. Se definido, faz com que as linhas com localhostsejam ignoradas de acordo com o registro. O seguinte pode ser visto no log de erros: "Entrada de 'usuário' 'root @ localhost' ignorada no modo --skip-name-resolve." . Isso significa nenhuma conexão por meio do soquete de domínio Unix. Mas este não é o caso empiricamente. localhostagora significa SOMENTE o soquete de domínio Unix e não corresponde mais a 127.0.0.1.

skip-name-resolve está fora:

  • Conecte usando o soquete: OK
  • Conectar de 127.0.0.1: OK

skip-name-resolve está ligado:

  • Conecte usando o soquete: OK
  • Conectar de 127.0.0.1: FALHA

Caso 3: Host = '127.0.0.1'

update user set host='127.0.0.1' where user='foo';flush privileges;
  • Conecte usando o soquete: FAILURE
  • Conectar de 127.0.0.1: OK

Caso 4: Host = ''

update user set host='' where user='foo';flush privileges;
  • Conecte usando o soquete: OK
  • Conectar de 127.0.0.1: OK

(De acordo com MySQL 5.7: 6.2.4 Controle de acesso, Estágio 1: Verificação de conexão , a string vazia '' também significa “qualquer host”, mas é classificada após '%'. )

Caso 5: Host = '192.168.0.1' (teste extra)

('192.168.0.1' é um dos endereços IP da minha máquina, altere apropriadamente no seu caso)

update user set host='192.168.0.1' where user='foo';flush privileges;
  • Conecte usando o soquete: FAILURE
  • Conectar de 127.0.0.1: FALHA

mas

  • Conecte-se usando mysql -pbar -ufoo -h192.168.0.1: OK (!)

Este último porque esta é realmente uma conexão TCP proveniente 192.168.0.1, conforme revelado por lsof:

TCP 192.168.0.1:37059->192.168.0.1:mysql (ESTABLISHED)

Caso Edge A: Host = '0.0.0.0'

update user set host='0.0.0.0' where user='foo';flush privileges;
  • Conecte usando o soquete: FAILURE
  • Conectar de 127.0.0.1: FALHA

Edge Case B: Host = '255.255.255.255'

update user set host='255.255.255.255' where user='foo';flush privileges;
  • Conecte usando o soquete: FAILURE
  • Conectar de 127.0.0.1: FALHA

Edge Case C: Host = '127.0.0.2'

(127.0.0.2 é um endereço de loopback perfeitamente válido equivalente a 127.0.0.1 conforme definido em RFC6890 )

update user set host='127.0.0.2' where user='foo';flush privileges;
  • Conecte usando o soquete: FAILURE
  • Conectar de 127.0.0.1: FALHA

Curiosamente:

  • mysql -pbar -ufoo -h127.0.0.2conecta de 127.0.0.1e é FALHA
  • mysql -pbar -ufoo -h127.0.0.2 --bind-address=127.0.0.2 está bem

Limpar

delete from user where user='foo';flush privileges;

Termo aditivo

Para ver o que realmente está na mysql.usertabela, que é uma das tabelas de permissão, use:

SELECT SUBSTR(password,1,6) as password, user, host,
Super_priv AS su,
Grant_priv as gr,
CONCAT(Select_priv, Lock_tables_priv) AS selock,
CONCAT(Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv) AS modif,
CONCAT(References_priv, Index_priv, Alter_priv) AS ria,
CONCAT(Create_tmp_table_priv, Create_view_priv, Show_view_priv) AS views,
CONCAT(Create_routine_priv, Alter_routine_priv, Execute_priv, Event_priv, Trigger_priv) AS funcs,
CONCAT(Repl_slave_priv, Repl_client_priv) AS replic,
CONCAT(Shutdown_priv, Process_priv, File_priv, Show_db_priv, Reload_priv, Create_user_priv) AS admin
FROM user ORDER BY user, host;

isto dá:

+----------+----------+-----------+----+----+--------+-------+-----+-------+-------+--------+--------+
    | password | user     | host      | su | gr | selock | modif | ria | views | funcs | replic | admin  |
    +----------+----------+-----------+----+----+--------+-------+-----+-------+-------+--------+--------+
    | *E8D46   | foo      |           | N  | N  | NN     | NNNNN | NNN | NNN   | NNNNN | NN     | NNNNNN |

Da mesma forma para a mesa mysql.db:

SELECT host,db,user, 
       Grant_priv as gr,
       CONCAT(Select_priv, Lock_tables_priv) AS selock, 
       CONCAT(Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv) AS modif, 
       CONCAT(References_priv, Index_priv, Alter_priv) AS ria, 
       CONCAT(Create_tmp_table_priv, Create_view_priv, Show_view_priv) AS views, 
       CONCAT(Create_routine_priv, Alter_routine_priv, Execute_priv) AS funcs 
       FROM db ORDER BY user, db, host;
David Tonhofer
fonte
7
Isso requer uma conclusão que deixe claro o que o resto da resposta está realmente dizendo, sem a necessidade de entender o código.
Prometheus
8

Se você quiser se conectar a user@'%'partir do localhost, use mysql -h192.168.0.1 -uuser -p.

alex
fonte
6

O símbolo de porcentagem significa: qualquer host, incluindo conexões remotas e locais.

O localhost permite apenas conexões locais.

(então, para começar, se você não precisa de conexões remotas com seu banco de dados, você pode se livrar do usuário appuser @ '%' imediatamente)

Então, sim, eles estão se sobrepondo, mas ...

... há uma razão para definir os dois tipos de contas, isso é explicado nos documentos do mysql: http://dev.mysql.com/doc/refman/5.7/en/adding-users.html .

Se você tiver um usuário anônimo em seu host local, que poderá identificar com:

select Host from mysql.user where User='' and Host='localhost';

e se você apenas criar o usuário appuser @ '%' (e não o appuser @ 'localhost'), então quando o usuário appuser mysql se conecta a partir do host local, a conta de usuário anônima é usada (tem precedência sobre seu appuser @ '%' do utilizador).

E a correção para isso é (como se pode imaginar) criar o appuser @ 'localhost' (que é mais específico que o usuário anônimo do host local e será usado se o seu appuser se conectar a partir do localhost).

ling
fonte
5

Indo para fornecer uma resposta ligeiramente diferente das fornecidas até agora.

Se você tiver uma linha para um usuário anônimo de localhost em sua tabela de usuários ''@'localhost', isso será tratado como mais específico do que seu usuário com host com curinga 'user'@'%'. É por isso que é necessário também fornecer 'user'@'localhost'.

Você pode ver isso explicado com mais detalhes no final desta página .

Joshua Walsh
fonte