Używanie% dla hosta podczas tworzenia użytkownika MySQL

93

Baza danych MySQL potrzebuje dwóch użytkowników: appuser i support.
Jeden z twórców aplikacji nalega, abym utworzył cztery konta dla tych użytkowników:

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

Na całe życie nie mogę zrozumieć, dlaczego sądzi, że tego potrzebujemy. Czy użycie symbolu wieloznacznego jako hosta nie zajmie się „hostem lokalnym”?

Jakieś pomysły?

(Używając MySQL 5.5 tutaj)

Ed Manet
źródło

Odpowiedzi:

106

localhostjest wyjątkowy w MySQL, oznacza połączenie przez gniazdo UNIX (lub, jak sądzę, nazwane potoki w systemie Windows) w przeciwieństwie do gniazda TCP / IP. Używanie %jako hosta nie obejmuje localhost, stąd potrzeba jawnego określenia tego.

aleroot
źródło
W jakiej wersji? W MySQL 5.5.35 „%” pasuje również do localhost.
depquid
4
Nie tylko "localhost" łączy się przez lokalne gniazdo, 127.0.0.1 (które nie używa gniazda) nie będzie pasować do%, ale zamiast tego również localhost. Widziałem to z haproxy dzisiaj.
Phillipp,
33

Jak @nos zauważył w komentarzach do aktualnie zaakceptowanej odpowiedzi na to pytanie, przyjęta odpowiedź jest nieprawidłowa.

Tak, istnieje różnica między korzystaniem z hosta konta użytkownika %a korzystaniem localhostz hosta konta użytkownika w przypadku łączenia się przez gniazdo zamiast standardowego połączenia TCP / IP.

Wartość hosta %nie obejmuje localhostgniazd i dlatego musi zostać określona, ​​jeśli chcesz łączyć się przy użyciu tej metody.

John Kary
źródło
15

Po prostu przetestujmy.

Połącz się jako superużytkownik, a następnie:

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

i wtedy

USE mysql;

Ustawiać

Utwórz użytkownika fooz hasłem bardo testowania:

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

Połączyć

Aby połączyć się z Unix Domain Socket (tj. Potokiem I / O, który jest nazwany przez wpis systemu plików /var/run/mysqld/mysqld.socklub coś podobnego), uruchom to w wierszu poleceń (użyj --protocolopcji, aby upewnić się podwójnie)

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

Można się spodziewać, że powyższe dopasowanie „użytkownik pochodzi z hosta lokalnego”, ale z pewnością nie „użytkownik pochodzi z 127.0.0.1”.

Aby zamiast tego połączyć się z serwerem z „127.0.0.1”, uruchom to w wierszu poleceń

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

Jeśli pominiesz --protocol=TCP, mysqlpolecenie nadal będzie próbowało użyć gniazda domeny Unix. Możesz też powiedzieć:

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

Dwie próby połączenia w jednej linii:

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"

(hasło jest ustawione w środowisku, tak aby było przekazywane do mysql procesu)

Weryfikacja w przypadku wątpliwości

Aby naprawdę sprawdzić, czy połączenie przechodzi przez gniazdo TCP / IP lub gniazdo domeny Unix

  1. pobierz PID procesu klienta mysql, sprawdzając dane wyjściowe ps faux
  2. biegać lsof -n -p<yourpid>.

Zobaczysz coś takiego:

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

lub

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

Więc:

Przypadek 0: Host = „10 .10.10.10” (test zerowy)

update user set host='10.10.10.10' where user='foo'; flush privileges;
  • Podłącz za pomocą gniazda: FAILURE
  • Połącz z 127.0.0.1: FAILURE

Przypadek 1: Host = „%”

update user set host='%' where user='foo'; flush privileges;
  • Podłącz za pomocą gniazda: OK
  • Połącz z 127.0.0.1: OK

Przypadek 2: Host = 'localhost'

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

Zachowanie jest różne i najwyraźniej zależy od tego skip-name-resolve. Jeśli jest ustawiona, powoduje localhostignorowanie wierszy z zgodnie z dziennikiem. W dzienniku błędów można zobaczyć następujące informacje: „Wpis„ użytkownika ”„ root @ localhost ”został zignorowany w trybie --skip-name-solution.” . Oznacza to brak łączenia się przez gniazdo domeny Unix. Ale empirycznie tak nie jest.localhostteraz oznacza TYLKO Unix Domain Socket i już nie pasuje do 127.0.0.1.

skip-name-resolve jest wyłączony:

  • Podłącz za pomocą gniazda: OK
  • Połącz z 127.0.0.1: OK

skip-name-resolve jest włączony:

  • Podłącz za pomocą gniazda: OK
  • Połącz z 127.0.0.1: FAILURE

Przypadek 3: Host = „127.0.0.1”

update user set host='127.0.0.1' where user='foo';flush privileges;
  • Podłącz za pomocą gniazda: FAILURE
  • Połącz z 127.0.0.1: OK

Przypadek 4: Host = ''

update user set host='' where user='foo';flush privileges;
  • Podłącz za pomocą gniazda: OK
  • Połącz z 127.0.0.1: OK

(Zgodnie z MySQL 5.7: 6.2.4 Kontrola dostępu, etap 1: weryfikacja połączenia , pusty ciąg „” oznacza również „dowolny host”, ale sortuje po „%” ).

Przypadek 5: Host = „192.168.0.1” (dodatkowy test)

(„192.168.0.1” to jeden z adresów IP mojego komputera, zmień odpowiednio w swoim przypadku)

update user set host='192.168.0.1' where user='foo';flush privileges;
  • Podłącz za pomocą gniazda: FAILURE
  • Połącz z 127.0.0.1: FAILURE

ale

  • Połącz za pomocą mysql -pbar -ufoo -h192.168.0.1: OK (!)

To drugie, ponieważ jest to w rzeczywistości połączenie TCP 192.168.0.1, jak ujawniono lsof:

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

Przypadek skrajny A: Host = „0.0.0.0”

update user set host='0.0.0.0' where user='foo';flush privileges;
  • Podłącz za pomocą gniazda: FAILURE
  • Połącz z 127.0.0.1: FAILURE

Przypadek krawędzi B: Host = „255.255.255.255”

update user set host='255.255.255.255' where user='foo';flush privileges;
  • Podłącz za pomocą gniazda: FAILURE
  • Połącz z 127.0.0.1: FAILURE

Edge Case C: Host = „127.0.0.2”

(127.0.0.2 to doskonale poprawny adres sprzężenia zwrotnego odpowiadający 127.0.0.1 zdefiniowanemu w RFC6890 )

update user set host='127.0.0.2' where user='foo';flush privileges;
  • Podłącz za pomocą gniazda: FAILURE
  • Połącz z 127.0.0.1: FAILURE

Co ciekawe:

  • mysql -pbar -ufoo -h127.0.0.2łączy się z 127.0.0.1i jest FAILURE
  • mysql -pbar -ufoo -h127.0.0.2 --bind-address=127.0.0.2 jest OK

Sprzątać

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

Uzupełnienie

Aby zobaczyć, co faktycznie znajduje się w mysql.usertabeli, która jest jedną z tabel uprawnień, użyj:

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;

to daje:

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

Podobnie dla tabeli 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
źródło
6
Wymaga to wniosku, który wyjaśnia, co tak naprawdę mówi reszta odpowiedzi, bez konieczności rozumienia kodu.
Prometeusz
7

Jeśli chcesz połączyć się user@'%'z localhost użyj mysql -h192.168.0.1 -uuser -p.

Alex
źródło
5

Zamierzam udzielić nieco innej odpowiedzi niż dotychczas.

Jeśli masz wiersz dla anonimowego użytkownika z hosta lokalnego w tabeli użytkowników, ''@'localhost'będzie to traktowane jako bardziej szczegółowe niż twój użytkownik z hostem z symbolem wieloznacznym 'user'@'%'. Dlatego konieczne jest również zapewnienie 'user'@'localhost'.

Możesz zobaczyć to wyjaśnione bardziej szczegółowo na dole tej strony .

Joshua Walsh
źródło
5

Symbol procentu oznacza: dowolny host, w tym połączenia zdalne i lokalne.

Lokalny host zezwala tylko na połączenia lokalne.

(więc na początek, jeśli nie potrzebujesz zdalnych połączeń z bazą danych, możesz od razu pozbyć się użytkownika appuser @ '%')

Więc tak, pokrywają się, ale ...

... istnieje powód dla ustawienia obu typów kont, jest to wyjaśnione w dokumentacji mysql: http://dev.mysql.com/doc/refman/5.7/en/adding-users.html .

Jeśli masz anonimowego użytkownika na swoim hoście lokalnym, którego możesz rozpoznać za pomocą:

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

a jeśli po prostu utworzysz appuser użytkownika @ '%' (a nie jesteś appuser @ 'localhost'), to gdy użytkownik appuser mysql łączy się z lokalnego hosta, używane jest konto anonimowego użytkownika (ma pierwszeństwo przed twoim appuser @ „%” użytkownika).

Rozwiązaniem tego problemu jest (jak można się domyślić) utworzenie appuser @ 'localhost' (co jest bardziej szczegółowe niż anonimowy użytkownik lokalnego hosta i będzie używany, jeśli appuser połączy się z localhost).

molwa
źródło