ใช้% สำหรับโฮสต์เมื่อสร้างผู้ใช้ MySQL


93

ฐานข้อมูล MySQL ของฉันต้องการผู้ใช้สองคน: ผู้ใช้แอปและการสนับสนุน
นักพัฒนาแอปพลิเคชันคนหนึ่งยืนยันว่าฉันสร้างบัญชีสี่บัญชีสำหรับผู้ใช้เหล่านี้:

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

สำหรับชีวิตของฉันฉันคิดไม่ออกว่าทำไมเขาถึงคิดว่าเราต้องการสิ่งนี้ จะไม่ใช้สัญลักษณ์แทนเพราะโฮสต์ดูแล 'localhost'?

ความคิดใด ๆ ?

(ใช้ MySQL 5.5 ที่นี่)

คำตอบ:


106

localhostมีความพิเศษใน MySQL ซึ่งหมายถึงการเชื่อมต่อผ่านซ็อกเก็ต UNIX (หรือชื่อไปป์บน Windows ฉันเชื่อว่า) ตรงข้ามกับซ็อกเก็ต TCP / IP การใช้%เป็นโฮสต์ไม่รวมlocalhostด้วยเหตุนี้จึงจำเป็นต้องระบุอย่างชัดเจน


ในเวอร์ชันใด ใน MySQL 5.5.35 "%" จะตรงกับ localhost ด้วย
depquid

4
"localhost" ไม่เพียงเชื่อมต่อผ่านซ็อกเก็ตท้องถิ่น 127.0.0.1 (ซึ่งไม่ใช้ซ็อกเก็ต) จะไม่จับคู่% แต่ localhost แทนเช่นกัน เห็นว่ามีการติดตั้ง haproxy วันนี้.
Phillipp

33

ดังที่ @nos ระบุไว้ในความคิดเห็นของคำตอบที่ยอมรับในปัจจุบันสำหรับคำถามนี้คำตอบที่ยอมรับนั้นไม่ถูกต้อง

ใช่มีความแตกต่างระหว่างการใช้%และlocalhostสำหรับโฮสต์บัญชีผู้ใช้เมื่อเชื่อมต่อผ่านการเชื่อมต่อซ็อกเก็ตแทนการเชื่อมต่อ TCP / IP มาตรฐาน

ค่าโฮสต์ของ%ไม่รวมlocalhostสำหรับซ็อกเก็ตดังนั้นจึงต้องระบุหากคุณต้องการเชื่อมต่อโดยใช้วิธีดังกล่าว


16

ลองทดสอบดู

เชื่อมต่อเป็น superuser จากนั้น:

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

แล้ว

USE mysql;

ติดตั้ง

สร้างผู้ใช้fooด้วยรหัสผ่านbarสำหรับการทดสอบ:

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

เชื่อมต่อ

ในการเชื่อมต่อกับ Unix Domain Socket (เช่นไปป์ I / O ที่ตั้งชื่อโดยรายการระบบไฟล์/var/run/mysqld/mysqld.sockหรือบางส่วน) ให้รันสิ่งนี้ในบรรทัดคำสั่ง (ใช้--protocolตัวเลือกเพื่อให้แน่ใจเป็นสองเท่า)

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

เราคาดหวังว่าการจับคู่ข้างต้น "ผู้ใช้มาจาก localhost" แต่ไม่ใช่ "ผู้ใช้มาจาก 127.0.0.1"

หากต้องการเชื่อมต่อกับเซิร์ฟเวอร์จาก "127.0.0.1" แทนให้เรียกใช้สิ่งนี้ในบรรทัดคำสั่ง

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

หากคุณไม่--protocol=TCPใช้mysqlคำสั่งจะยังคงพยายามใช้ซ็อกเก็ตโดเมน Unix คุณยังสามารถพูดว่า:

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

การเชื่อมต่อสองครั้งพยายามในหนึ่งบรรทัด:

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"

(รหัสผ่านถูกตั้งค่าในสภาพแวดล้อมเพื่อให้ผ่านไปยังmysqlกระบวนการ)

การตรวจสอบในกรณีที่มีข้อสงสัย

เพื่อตรวจสอบว่าการเชื่อมต่อผ่านซ็อกเก็ต TCP / IP หรือซ็อกเก็ต Unix Domain

  1. รับ PID ของกระบวนการไคลเอนต์ mysql โดยตรวจสอบผลลัพธ์ของ ps faux
  2. วิ่งlsof -n -p<yourpid>.

คุณจะเห็นสิ่งต่างๆเช่น:

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

หรือ

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

ดังนั้น:

กรณี 0: โฮสต์ = '10 .10.10.10 '(การทดสอบค่าว่าง)

update user set host='10.10.10.10' where user='foo'; flush privileges;
  • เชื่อมต่อโดยใช้ซ็อกเก็ต: FAILURE
  • เชื่อมต่อจาก 127.0.0.1: FAILURE

กรณีที่ 1: โฮสต์ = '%'

update user set host='%' where user='foo'; flush privileges;
  • เชื่อมต่อโดยใช้ซ็อกเก็ต: ตกลง
  • เชื่อมต่อจาก 127.0.0.1: ตกลง

กรณีที่ 2: โฮสต์ = 'localhost'

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

พฤติกรรมแตกต่างกันไปskip-name-resolveและเห็นได้ชัดว่าขึ้นอยู่กับ หากตั้งค่าไว้จะทำให้บรรทัดlocalhostที่ถูกละเว้นตามบันทึก ข้อมูลต่อไปนี้สามารถเห็นได้ในบันทึกข้อผิดพลาด: "'user' entry 'root @ localhost' ถูกละเว้นในโหมด --skip-name-resolution" . ซึ่งหมายความว่าไม่มีการเชื่อมต่อผ่าน Unix Domain Socket แต่ในเชิงประจักษ์ไม่เป็นเช่นนั้น localhostตอนนี้หมายถึงซ็อกเก็ตโดเมน Unix เท่านั้นและไม่ตรงกับ 127.0.0.1 อีกต่อไป

skip-name-resolve ปิด:

  • เชื่อมต่อโดยใช้ซ็อกเก็ต: ตกลง
  • เชื่อมต่อจาก 127.0.0.1: ตกลง

skip-name-resolve เปิดอยู่:

  • เชื่อมต่อโดยใช้ซ็อกเก็ต: ตกลง
  • เชื่อมต่อจาก 127.0.0.1: FAILURE

กรณีที่ 3: โฮสต์ = '127.0.0.1'

update user set host='127.0.0.1' where user='foo';flush privileges;
  • เชื่อมต่อโดยใช้ซ็อกเก็ต: FAILURE
  • เชื่อมต่อจาก 127.0.0.1: ตกลง

กรณีที่ 4: โฮสต์ = ''

update user set host='' where user='foo';flush privileges;
  • เชื่อมต่อโดยใช้ซ็อกเก็ต: ตกลง
  • เชื่อมต่อจาก 127.0.0.1: ตกลง

(ตามที่MySQL 5.7: 6.2.4 การควบคุมการเข้าถึงขั้นตอนที่ 1: การเชื่อมต่อการตรวจสอบ , ว่างสตริง '' ยังหมายถึง“เจ้าภาพใด ๆ” แต่หลังจากที่ทุกประเภท '%'. )

กรณีที่ 5: โฮสต์ = '192.168.0.1' (การทดสอบเพิ่มเติม)

('192.168.0.1' เป็นหนึ่งในที่อยู่ IP ของเครื่องของฉันเปลี่ยนแปลงอย่างเหมาะสมในกรณีของคุณ)

update user set host='192.168.0.1' where user='foo';flush privileges;
  • เชื่อมต่อโดยใช้ซ็อกเก็ต: FAILURE
  • เชื่อมต่อจาก 127.0.0.1: FAILURE

แต่

  • เชื่อมต่อโดยใช้mysql -pbar -ufoo -h192.168.0.1: ตกลง (!)

ประการหลังเพราะนี่คือการเชื่อมต่อ TCP ที่มาจาก192.168.0.1ที่เปิดเผยโดยlsof:

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

Edge Case A: โฮสต์ = '0.0.0.0'

update user set host='0.0.0.0' where user='foo';flush privileges;
  • เชื่อมต่อโดยใช้ซ็อกเก็ต: FAILURE
  • เชื่อมต่อจาก 127.0.0.1: FAILURE

Edge Case B: โฮสต์ = '255.255.255.255'

update user set host='255.255.255.255' where user='foo';flush privileges;
  • เชื่อมต่อโดยใช้ซ็อกเก็ต: FAILURE
  • เชื่อมต่อจาก 127.0.0.1: FAILURE

ขอบเคส C: โฮสต์ = '127.0.0.2'

(127.0.0.2 เป็นที่อยู่ลูปแบ็คที่ถูกต้องสมบูรณ์เทียบเท่ากับ 127.0.0.1 ตามที่กำหนดในRFC6890 )

update user set host='127.0.0.2' where user='foo';flush privileges;
  • เชื่อมต่อโดยใช้ซ็อกเก็ต: FAILURE
  • เชื่อมต่อจาก 127.0.0.1: FAILURE

ที่น่าสนใจ:

  • mysql -pbar -ufoo -h127.0.0.2เชื่อมต่อจาก127.0.0.1และล้มเหลว
  • mysql -pbar -ufoo -h127.0.0.2 --bind-address=127.0.0.2 ก็โอเค

ทำความสะอาด

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

ภาคผนวก

หากต้องการดูสิ่งที่อยู่ในmysql.userตารางซึ่งเป็นหนึ่งในตารางสิทธิ์ให้ใช้:

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;

สิ่งนี้ให้:

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

ในทำนองเดียวกันสำหรับตาราง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;

6
สิ่งนี้ต้องการข้อสรุปที่ทำให้ชัดเจนว่าคำตอบที่เหลือพูดถึงอะไรโดยไม่จำเป็นต้องเข้าใจรหัส
Prometheus


5

ไปเพื่อให้คำตอบที่แตกต่างกันเล็กน้อยกับที่ให้ไว้จนถึงตอนนี้

ถ้าคุณมีแถวสำหรับผู้ใช้ที่ไม่ระบุชื่อจาก localhost ในตารางผู้ใช้ของคุณแล้วนี้จะถือว่าเป็นเฉพาะเจาะจงมากขึ้นกว่าผู้ใช้ของคุณกับโฮสต์''@'localhost' wildcard'd 'user'@'%'ด้วยเหตุนี้จึงจำเป็นต้องให้'user'@'localhost'ด้วย

คุณสามารถดูคำอธิบายโดยละเอียดเพิ่มเติมได้ที่ด้านล่างของหน้านี้


5

สัญลักษณ์เปอร์เซ็นต์หมายถึงโฮสต์ใด ๆ รวมถึงการเชื่อมต่อระยะไกลและในพื้นที่

localhost อนุญาตเฉพาะการเชื่อมต่อภายใน

(เพื่อเริ่มต้นหากคุณไม่ต้องการการเชื่อมต่อระยะไกลกับฐานข้อมูลของคุณคุณสามารถกำจัดผู้ใช้ appuser @ '%' ได้ทันที)

ใช่มันทับซ้อนกัน แต่ ...

... มีเหตุผลสำหรับการตั้งค่าทั้งสองประเภทของบัญชีนี้จะมีการอธิบายในเอกสาร MySQL นี้: http://dev.mysql.com/doc/refman/5.7/en/adding-users.html

หากคุณมีผู้ใช้ที่ไม่ระบุชื่อบน localhost ของคุณซึ่งคุณสามารถมองเห็นได้ด้วย:

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

และหากคุณเพิ่งสร้าง appuser ผู้ใช้ @ '%' (และคุณไม่ใช่ appuser @ 'localhost') จากนั้นเมื่อผู้ใช้ appuser mysql เชื่อมต่อจากโฮสต์ภายในระบบจะใช้บัญชีผู้ใช้ที่ไม่ระบุชื่อ (มีความสำคัญเหนือ appuser @ ของคุณ ผู้ใช้ '%')

และการแก้ไขสำหรับสิ่งนี้คือ (อย่างที่ใคร ๆ ก็เดาได้) เพื่อสร้าง appuser @ 'localhost' (ซึ่งเฉพาะเจาะจงมากขึ้นสำหรับผู้ใช้ที่ไม่ระบุชื่อโฮสต์ในเครื่องและจะถูกใช้หากผู้ใช้แอปของคุณเชื่อมต่อจาก localhost)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.