文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 參考手冊  /  ...  /  存取控制,階段 1:連線驗證

8.2.6 存取控制,階段 1:連線驗證

當您嘗試連線到 MySQL 伺服器時,伺服器會根據下列條件接受或拒絕連線

  • 您的身分以及您是否可以透過提供適當的憑證來驗證它。

  • 您的帳戶是否已鎖定或解除鎖定。

伺服器會先檢查憑證,然後檢查帳戶鎖定狀態。在任何一個步驟發生錯誤都會導致伺服器完全拒絕您的存取。否則,伺服器會接受連線,然後進入階段 2 並等待請求。

伺服器會使用 user 表中的欄位執行身分和憑證檢查,只有在滿足以下條件時才會接受連線

  • 用戶端主機名稱和使用者名稱與某些 user 表列中的 HostUser 欄位相符。有關允許的 HostUser 值的規則,請參閱 第 8.2.4 節,「指定帳戶名稱」

  • 用戶端會提供該列中指定的憑證(例如,密碼),如 authentication_string 欄位所示。憑證會使用 plugin 欄位中命名的驗證外掛程式進行解釋。

  • 該列表示帳戶已解除鎖定。鎖定狀態記錄在 account_locked 欄位中,其值必須為 'N'。可以使用 CREATE USERALTER USER 陳述式設定或變更帳戶鎖定。

您的身分基於兩個資訊

  • 您的 MySQL 使用者名稱。

  • 您連線的用戶端主機。

如果 User 欄位值為非空白,則傳入連線的使用者名稱必須完全符合。如果 User 值為空白,則符合任何使用者名稱。如果符合傳入連線的 user 資料表列的使用者名稱為空白,則該使用者會被視為沒有名稱的匿名使用者,而不是具有用戶端實際指定名稱的使用者。這表示在連線期間(即在第二階段)的所有進一步存取檢查都將使用空白的使用者名稱。

authentication_string 欄位可以為空白。這不是萬用字元,並不表示符合任何密碼。它表示使用者必須在不指定密碼的情況下連線。驗證用戶端的外掛程式實作的驗證方法可能會也可能不會使用 authentication_string 欄位中的密碼。在這種情況下,也可能使用外部密碼來驗證 MySQL 伺服器。

儲存在 user 資料表的 authentication_string 欄位中的非空白密碼值是加密的。MySQL 不會將密碼儲存為明文,讓任何人都能看到。相反地,嘗試連線的使用者所提供的密碼會被加密(使用帳戶驗證外掛程式實作的密碼雜湊方法)。然後,在連線過程中,會使用加密後的密碼來檢查密碼是否正確。這是在加密後的密碼永遠不會在連線中傳輸的情況下完成的。請參閱第 8.2.1 節,「帳戶使用者名稱和密碼」

從 MySQL 伺服器的角度來看,加密後的密碼是真正的密碼,因此您絕對不應該讓任何人存取它。特別是,不要讓非管理使用者讀取 mysql 系統資料庫中的資料表

下表顯示 user 資料表中 UserHost 值的各種組合如何應用於傳入連線。

User Host 允許的連線
'fred' 'h1.example.net' h1.example.net 連線的 fred
'' 'h1.example.net' h1.example.net 連線的任何使用者
'fred' '%' 從任何主機連線的 fred
'' '%' 從任何主機連線的任何使用者
'fred' '%.example.net' example.net 網域中的任何主機連線的 fred
'fred' 'x.example.%' x.example.netx.example.comx.example.edu 等連線的 fred;這可能沒有用
'fred' '198.51.100.177' 從具有 IP 位址 198.51.100.177 的主機連線的 fred
'fred' '198.51.100.%' 198.51.100 C 類子網路中的任何主機連線的 fred
'fred' '198.51.100.0/255.255.255.0' 與上一個範例相同

傳入連線的用戶端主機名稱和使用者名稱有可能與 user 資料表中的多列相符。上述範例集展示了這一點:顯示的幾個條目符合來自 h1.example.netfred 的連線。

當有多個符合項時,伺服器必須決定要使用哪一個。它會按照以下方式解決此問題

  • 每當伺服器將 user 資料表讀取到記憶體時,它會對這些列進行排序。

  • 當用戶端嘗試連線時,伺服器會依排序順序搜尋這些列。

  • 伺服器會使用第一個符合用戶端主機名稱和使用者名稱的列。

伺服器會使用排序規則,先排序具有最特定 Host 值的列

  • 實體的 IP 位址和主機名稱是最特定的。

  • 主機部分具有 IP 位址的帳戶具有以下特定順序

    • 主機部分以 IP 位址給出的帳戶

      CREATE USER 'user_name'@'127.0.0.1';
      CREATE USER 'user_name'@'198.51.100.44';
    • 主機部分以使用 CIDR 表示法的 IP 位址給出的帳戶

      CREATE USER 'user_name'@'192.0.2.21/8';
      CREATE USER 'user_name'@'198.51.100.44/16';
    • 主機部分以使用子網路遮罩的 IP 位址給出的帳戶

      CREATE USER 'user_name'@'192.0.2.0/255.255.255.0';
      CREATE USER 'user_name'@'198.51.0.0/255.255.0.0';
  • 模式 '%' 表示任何主機,且最不特定。

  • 空字串 '' 也表示任何主機,但在 '%' 之後排序。

非 TCP(socket 檔案、具名管道和共用記憶體)連線會被視為本機連線,如果存在任何此類帳戶,則會比對 localhost 的主機部分,否則會比對符合 localhost 的萬用字元主機部分(例如,local%l%%)。

'%' 視為等同於 localhost 的處理方式已過時;您應該預期此行為將從未來版本的 MySQL 中移除。

具有相同 Host 值的列會先排序具有最特定 User 值的列。空白的 User 值表示任何使用者,且最不特定,因此對於具有相同 Host 值的列,非匿名使用者會在匿名使用者之前排序。

對於具有同等特定 HostUser 值的列,順序是不確定的。

若要瞭解其運作方式,假設 user 資料表如下所示

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-

當伺服器將資料表讀取到記憶體時,它會使用剛描述的規則對這些列進行排序。排序後的結果如下

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-

當用戶端嘗試連線時,伺服器會搜尋排序後的列,並使用找到的第一個符合項。對於來自 localhostjeffrey 連線,資料表中的兩列符合:HostUser 值為 'localhost''' 的列,以及值為 '%''jeffrey' 的列。 'localhost' 列在排序順序中首先出現,因此這是伺服器使用的列。

這是另一個範例。假設 user 資料表如下所示

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| h1.example.net |          | ...
+----------------+----------+-

排序後的資料表如下所示

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| h1.example.net |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

第一列符合來自 h1.example.net 的任何使用者的連線,而第二列符合來自任何主機的 jeffrey 的連線。

請注意

一種常見的誤解是認為,對於給定的使用者名稱,當伺服器嘗試尋找連線的符合項時,會先使用明確命名該使用者的所有列。這是不正確的。前面的範例說明了這一點,其中來自 h1.example.netjeffrey 連線首先比對的是沒有使用者名稱的列,而不是將 'jeffrey' 作為 User 欄位值的列。因此,jeffrey 會被驗證為匿名使用者,即使他在連線時指定了使用者名稱。

如果您能夠連線到伺服器,但您的權限與您預期的不符,則您可能正在被驗證為其他帳戶。若要找出伺服器用於驗證您的帳戶,請使用 CURRENT_USER() 函數。(請參閱第 14.15 節,「資訊函數」。)它會以 user_name@host_name 格式傳回一個值,指出符合的 user 資料表列中的 UserHost 值。假設 jeffrey 連線並發出以下查詢

mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| @localhost     |
+----------------+

這裡顯示的結果表示符合的 user 資料表列具有空白的 User 欄位值。換句話說,伺服器將 jeffrey 視為匿名使用者。

診斷驗證問題的另一種方法是列印出 user 資料表,並手動排序它,以查看首先進行符合項的位置。