Verwenden von% als Host beim Erstellen eines MySQL-Benutzers

89

Meine MySQL-Datenbank benötigt zwei Benutzer: Appuser und Support.
Einer der Anwendungsentwickler besteht darauf, dass ich vier Konten für diese Benutzer erstelle:

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

Für mein Leben kann ich nicht herausfinden, warum er glaubt, dass wir das brauchen. Würde sich die Verwendung des Platzhalters als Host nicht um den 'localhost' kümmern?

Irgendwelche Ideen?

(Verwenden von MySQL 5.5 hier)

Ed Manet
quelle

Antworten:

105

localhostist etwas Besonderes in MySQL und bedeutet eine Verbindung über einen UNIX-Socket (oder Named Pipes unter Windows, glaube ich) im Gegensatz zu einem TCP / IP-Socket. Die Verwendung %als Host ist nicht enthalten localhost, daher muss diese explizit angegeben werden.

Aleroot
quelle
In welcher Version? In MySQL 5.5.35 stimmt "%" auch mit localhost überein.
depquid
4
"Localhost" stellt nicht nur eine Verbindung über den lokalen Socket her, 127.0.0.1 (der den Socket nicht verwendet) stimmt nicht mit% überein, sondern auch mit localhost. Habe das heute mit einer Haproxy-Installation gesehen.
Phillipp
32

Wie @nos in den Kommentaren der aktuell akzeptierten Antwort auf diese Frage hervorhob, ist die akzeptierte Antwort falsch.

Ja, es gibt einen Unterschied zwischen %undlocalhost für den Host des Benutzerkontos, wenn eine Verbindung über eine Socket-Verbindung anstelle einer Standard-TCP / IP-Verbindung hergestellt wird.

Ein Hostwert von %ist localhostfür Sockets nicht enthalten und muss daher angegeben werden, wenn Sie mit dieser Methode eine Verbindung herstellen möchten.

John Kary
quelle
16

Lassen Sie uns einfach testen.

Als Superuser verbinden und dann:

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

und dann

USE mysql;

Konfiguration

Erstellen Sie einen Benutzer foomit einem Kennwort barzum Testen:

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

Verbinden

/var/run/mysqld/mysqld.sockFühren Sie dies in der Befehlszeile aus, um eine Verbindung zum Unix Domain Socket (dh zur E / A-Pipe, die durch den Dateisystemeintrag oder einen ähnlichen Namen benannt ist ) --protocolherzustellen (verwenden Sie die Option, um doppelt sicherzugehen).

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

Man erwartet, dass die obigen Übereinstimmungen "Benutzer kommt von localhost", aber sicherlich nicht "Benutzer kommt von 127.0.0.1".

Führen Sie dies in der Befehlszeile aus, um stattdessen über "127.0.0.1" eine Verbindung zum Server herzustellen

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

Wenn Sie dies weglassen, --protocol=TCPversucht der mysqlBefehl weiterhin, den Unix-Domänensocket zu verwenden. Du kannst auch sagen:

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

Die zwei Verbindungsversuche in einer Zeile:

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"

(Das Passwort wird in der Umgebung so festgelegt, dass es an das übergeben wird mysql Prozess übergeben wird.)

Überprüfung im Zweifelsfall

Um wirklich zu überprüfen, ob die Verbindung über einen TCP / IP-Socket oder einen Unix Domain-Socket erfolgt

  1. Ermitteln Sie die PID des MySQL-Client-Prozesses, indem Sie die Ausgabe von untersuchen ps faux
  2. laufen lsof -n -p<yourpid>.

Sie werden so etwas sehen wie:

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

oder

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

So:

Fall 0: Host = '10 .10.10.10 '(Nulltest)

update user set host='10.10.10.10' where user='foo'; flush privileges;
  • Verbindung über Steckdose: FAILURE
  • Verbindung von 127.0.0.1 herstellen: FEHLER

Fall 1: Host = '%'

update user set host='%' where user='foo'; flush privileges;
  • Verbindung über Steckdose herstellen: OK
  • Verbindung von 127.0.0.1 herstellen: OK

Fall 2: Host = 'localhost'

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

Das Verhalten variiert und dies hängt anscheinend davon ab skip-name-resolve. Wenn gesetzt, werden Zeilen mit localhostgemäß Protokoll ignoriert. Im Fehlerprotokoll wird Folgendes angezeigt : "'Benutzer' -Eintrag 'root @ localhost' wird im Auflösungsmodus --skip-name ignoriert." . Dies bedeutet, dass keine Verbindung über den Unix Domain Socket hergestellt wird. Dies ist jedoch empirisch nicht der Fall.localhostbedeutet jetzt NUR den Unix Domain Socket und stimmt nicht mehr mit 127.0.0.1 überein.

skip-name-resolve ist aus:

  • Verbindung über Steckdose herstellen: OK
  • Verbindung von 127.0.0.1 herstellen: OK

skip-name-resolve ist eingeschaltet:

  • Verbindung über Steckdose herstellen: OK
  • Verbindung von 127.0.0.1 herstellen: FEHLER

Fall 3: Host = '127.0.0.1'

update user set host='127.0.0.1' where user='foo';flush privileges;
  • Verbindung über Steckdose: FAILURE
  • Verbindung von 127.0.0.1 herstellen: OK

Fall 4: Host = ''

update user set host='' where user='foo';flush privileges;
  • Verbindung über Steckdose herstellen: OK
  • Verbindung von 127.0.0.1 herstellen: OK

(Laut MySQL 5.7: 6.2.4 Zugriffskontrolle, Phase 1: Verbindungsüberprüfung , die leere Zeichenkette ‚‘ bedeutet auch „jeden Host“ , sondern sortiert nach ‚%‘. )

Fall 5: Host = '192.168.0.1' (zusätzlicher Test)

('192.168.0.1' ist eine der IP-Adressen meines Computers. Ändern Sie sie in Ihrem Fall entsprechend.)

update user set host='192.168.0.1' where user='foo';flush privileges;
  • Verbindung über Steckdose: FAILURE
  • Verbindung von 127.0.0.1 herstellen: FEHLER

aber

  • Verbinden mit mysql -pbar -ufoo -h192.168.0.1: OK (!)

Letzteres, weil es sich tatsächlich um eine TCP-Verbindung handelt, von der 192.168.0.1Folgendes stammt lsof:

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

Randfall A: Host = '0.0.0.0'

update user set host='0.0.0.0' where user='foo';flush privileges;
  • Verbindung über Steckdose: FAILURE
  • Verbindung von 127.0.0.1 herstellen: FEHLER

Randfall B: Host = '255.255.255.255'

update user set host='255.255.255.255' where user='foo';flush privileges;
  • Verbindung über Steckdose: FAILURE
  • Verbindung von 127.0.0.1 herstellen: FEHLER

Randfall C: Host = '127.0.0.2'

(127.0.0.2 ist eine vollkommen gültige Loopback-Adresse, die 127.0.0.1 entspricht, wie in RFC6890 definiert. )

update user set host='127.0.0.2' where user='foo';flush privileges;
  • Verbindung über Steckdose: FAILURE
  • Verbindung von 127.0.0.1 herstellen: FEHLER

Interessant:

  • mysql -pbar -ufoo -h127.0.0.2 verbindet von 127.0.0.1 und ist FEHLER
  • mysql -pbar -ufoo -h127.0.0.2 --bind-address=127.0.0.2 ist in Ordnung

Aufräumen

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

Nachtrag

mysql.userVerwenden Sie Folgendes, um zu sehen, was sich tatsächlich in der Tabelle befindet, die eine der Berechtigungstabellen ist:

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;

das gibt:

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

Ähnliches gilt für die Tabelle 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
quelle
4
Dies erfordert eine Schlussfolgerung, die klar macht, was der Rest der Antwort tatsächlich sagt, ohne den Code verstehen zu müssen.
Prometheus
6

Wenn Sie user@'%'von localhost aus eine Verbindung herstellen möchten, verwenden Sie mysql -h192.168.0.1 -uuser -p.

Alex
quelle
5

Ich werde eine etwas andere Antwort geben als bisher.

Wenn Sie eine Zeile für einen anonymen Benutzer von localhost in Ihrer Benutzertabelle ''@'localhost'haben, wird diese als spezifischer behandelt als Ihr Benutzer mit Wildcard-Host 'user'@'%'. Deshalb ist es notwendig, auch bereitzustellen 'user'@'localhost'.

Sie können dies am Ende dieser Seite genauer erklären .

Joshua Walsh
quelle
4

Das Prozentzeichen bedeutet: Jeder Host, einschließlich Remote- und lokaler Verbindungen.

Der localhost erlaubt nur lokale Verbindungen.

(Wenn Sie also zunächst keine Remoteverbindungen zu Ihrer Datenbank benötigen, können Sie den Benutzer appuser @ '%' sofort entfernen.)

Also ja, sie überlappen sich, aber ...

... es gibt einen Grund für das Festlegen beider Kontotypen. Dies wird in den MySQL-Dokumenten erläutert: http://dev.mysql.com/doc/refman/5.7/en/adding-users.html .

Wenn Sie einen anonymen Benutzer auf Ihrem lokalen Host haben, mit dem Sie Folgendes erkennen können:

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

und wenn Sie nur den Benutzer appuser @ '%' erstellen (und nicht den appuser @ 'localhost'), wird das anonyme Benutzerkonto verwendet , wenn der Benutzer mysql des Antragstellers eine Verbindung vom lokalen Host herstellt (es hat Vorrang vor Ihrem appuser @) '%' Benutzer).

Die Lösung hierfür besteht (wie man sich vorstellen kann) darin, den appuser @ 'localhost' zu erstellen (der spezifischer ist als der anonyme Benutzer des lokalen Hosts und verwendet wird, wenn Ihr appuser eine Verbindung vom localhost herstellt).

ling
quelle