MYSQL 8.0之安全篇

歡迎關注筆者的微信公衆號


本文是筆者基於MYSQL8.0官方手冊並結合自身實際經驗編寫,不足之處歡迎指出。編寫不易,歡迎署名轉載。

密碼認證組件

MYSQL是一個組件式架構,MYSQL 8.0+默認啓用了密碼校驗組件validate_password,它強迫你設置很複雜的密碼以保證數據庫安全,對於個人來說,你不能設置如123456這樣的密碼,當你在設置這樣的密碼的時候會報如下錯誤:

ERROR 1819 (HY000): Your password does not satisfy the current policy requirements

筆者認爲這對於個人學習而言非常礙事,解決方案有兩種:

  • 修改密碼認證策略

  • 卸載密碼認證組件

修改密碼認證策略

官方文檔

  1. 查看當前認證策略

    mysql> SHOW VARIABLES LIKE 'validate_password.%';
    

在這裏插入圖片描述
這幾個認證策略就不一一解釋了,就是字面意思。

  1. 修改認證策略

    • 設置密碼長度爲4個字符

      mysql> SET GLOBAL validate_password_length = 4;
      
    • 設置認證策略低級

      SET GLOBAL validate_password_policy=LOW;
      

    其他的參數照着改就行,最後最好重啓一下服務器。

卸載密碼認證組件

官方文檔

筆者覺得MYSQL 8.0+默認的密碼認證策略非常礙事,所以直接卸載掉了;

  • 卸載密碼認證組件

    UNINSTALL COMPONENT 'file://component_validate_password';
    
  • 安裝密碼認證組件

    INSTALL COMPONENT 'file://component_validate_password';
    

密碼加密方式

官方文檔

問題

在MYSQL 8.0中包含了一下三種加密插件

  • caching_sha2_password

  • sha256_password

  • mysql_native_password

mysql_native_password插件相比,caching_sha2_passwordsha256_password身份驗證插件提供了更安全的密碼加密。且caching_sha2_password在性能上優於sha256_password,因此在MYSQL 8.0中caching_sha2_password成爲了默認的加密插件。

  • 修改MYSQL配置文件:/etc/my.cnf

    vim /etc/my.cnf
    ...
    [mysqld]
    default_authentication_plugin=mysql_native_password
    ...
    
  • 也可以在服務器啓動時添加命令行參數

     --default-authentication-plugin=mysql_native_password 加上  --initialize選項 或者 --initialize-insecure選項
    

這種方法是爲了兼容那些舊版本客戶端能連接到新版本的MYSQL服務器,最好的做法是不要更改服務端參數,而是升級客戶端,對於Java程序員來說,升級MYSQL驅動到8.0.9或更高的版本。

修改現有賬戶的加密方式

在MYSQL安裝的時候默認創建了'root'@'localhost'賬號,因此只要修改了賬戶的加密方式舊版的客戶端就可以通過此賬號密碼連接數據庫。

ALTER USER 'root'@'localhost'  IDENTIFIED WITH mysql_native_password  BY 'password';

訪問控制和賬戶管理

用戶名和密碼

官方文檔

默認情況下,MYSQL將用戶名和連接主機信息存儲在user表,位於mysql系統數據庫中。

注意

在MYSQL中,用戶名相同,連接主機不同被認爲是兩個賬號。

在這裏插入圖片描述
%表示這個賬號可從任何IP地址連接到服務器端。

默認情況下MYSQL只創建了'root'@'localhost'這個賬號,這隻能從本地連接到數據庫,如果要遠程連接需要創建新的用戶,連接主機IP設爲%,筆者這裏創建了replroot兩個可從遠程連接的賬戶。

下面是MYSQL關於用戶名和賬戶的一些注意事項:

  • MYSQL的用戶名最大長度限制爲32字符長度,這是一種硬編碼,無法更改。

  • MYSQL的賬戶密碼通過加密插件加密後存儲在user表中。

  • 如果用戶名和密碼使用了非ASCII字符,那麼可以在連接時通過MYSQL_SET_CHARSET_NAME選項指定。

  • MYSQL不支持ucs2, utf16, utf32,這三種字符集。

  • 如果在命令行中通過--password-p選項指定密碼,那麼密碼與選項之間不允許有空白。

    $ mysql -u finley -p db_name
    

    以上db_name會認爲是連接的數據庫名而不是密碼。

    $ mysql -u finley -ppassword db_name
    

MYSQL特權

官方文檔](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html)

MYSQL中的特權是MYSQL用來判斷賬戶是否具有能執行某種操作的憑證。

MYSQL中特權分三類:

  • 管理員特權,這是全局特權,可以操作整個服務器資源,root用戶就是管理員特權,可以操作所有資源

  • 數據庫特權,適用於數據庫及其中的所有對象。可以爲特定數據庫或全局授予這些特權,以便將它們應用於所有數據庫。

  • 可以爲數據庫中的特定對象,數據庫中給定類型的所有對象(例如數據庫中的所有表)或所有對象的全局對象授予表,索引,視圖和存儲例程等數據庫對象的特權。所有數據庫中給定類型的對象。

特權分類

MYSQL特權分爲靜態特權和動態特權,特權是靜態的(內置於服務器中)還是動態的(在運行時定義)對MYSQL行爲有不同的影響。特權是靜態還是動態會影響將其授予用戶帳戶和角色的可用性。

MYSQL的特權信息存儲在mysql數據庫中,具體的數據表下一章會介紹。

靜態特權
特權 表中字段 上下文
ALL PRIVILEGES Synonym for “all privileges” Server administration
ALTER Alter_priv Tables
ALTER ROUTINE Alter_routine_priv Stored routines
CREATE Create_priv Databases, tables, or indexes
CREATE ROLE Create_role_priv Server administration
CREATE ROUTINE Create_routine_priv Stored routines
CREATE TABLESPACE Create_tablespace_priv Server administration
CREATE TEMPORARY TABLES Create_tmp_table_priv Tables
CREATE USER Create_user_priv Server administration
CREATE VIEW Create_view_priv Views
DELETE Delete_priv Tables
DROP Drop_priv Databases, tables, or views
DROP ROLE Drop_role_priv Server administration
EVENT Event_priv Databases
EXECUTE Execute_priv Stored routines
FILE File_priv File access on server host
GRANT OPTION Grant_priv Databases, tables, or stored routines
INDEX Index_priv Tables
INSERT Insert_priv Tables or columns
LOCK TABLES Lock_tables_priv Databases
PROCESS Process_priv Server administration
PROXY See proxies_priv table Server administration
REFERENCES References_priv Databases or tables
RELOAD Reload_priv Server administration
REPLICATION CLIENT Repl_client_priv Server administration
REPLICATION SLAVE Repl_slave_priv Server administration
SELECT Select_priv Tables or columns
SHOW DATABASES Show_db_priv Server administration
SHOW VIEW Show_view_priv Views
SHUTDOWN Shutdown_priv Server administration
SUPER Super_priv Server administration
TRIGGER Trigger_priv Tables
UPDATE Update_priv Tables or columns
USAGE Synonym for "no privileges" Server administration
動態特權
特權 上下文
APPLICATION_PASSWORD_ADMIN Dual password administration
AUDIT_ADMIN Audit log administration
BACKUP_ADMIN Backup administration
BINLOG_ADMIN Backup and Replication administration
BINLOG_ENCRYPTION_ADMIN Backup and Replication administration
CLONE_ADMIN Clone administration
CONNECTION_ADMIN Server administration
ENCRYPTION_KEY_ADMIN Server administration
FIREWALL_ADMIN Firewall administration
FIREWALL_USER Firewall administration
GROUP_REPLICATION_ADMIN Replication administration
INNODB_REDO_LOG_ARCHIVE Redo log archiving administration
NDB_STORED_USER NDB Cluster
PERSIST_RO_VARIABLES_ADMIN Server administration
REPLICATION_APPLIER PRIVILEGE_CHECKS_USER for a replication channel
REPLICATION_SLAVE_ADMIN Replication administration
RESOURCE_GROUP_ADMIN Resource group administration
RESOURCE_GROUP_USER Resource group administration
ROLE_ADMIN Server administration
SESSION_VARIABLES_ADMIN Server administration
SET_USER_ID Server administration
SHOW_ROUTINE Server administration
SYSTEM_USER Server administration
SYSTEM_VARIABLES_ADMIN Server administration
TABLE_ENCRYPTION_ADMIN Server administration
VERSION_TOKEN_ADMIN Server administration
XA_RECOVER_ADMIN Server administration

有關特權的具體解釋請參看官方文檔,這裏就不一一解釋了,大部分特權正常情況下都不會用到的,用到時再參看官方解釋。

授權表

mysql系統數據庫中包含了幾個授權表,這些表包含有關用戶帳戶及其所擁有特權的信息。

注意
堅決禁止使用INSERT, UPDATE, DELETE語句直接修改這些表,這會有極大地風險,推薦使用 CREATE USER, GRANT, REVOKE 語句操作權限。

授權表預覽

以下授權表全部位於mysql數據庫中

在MySQL 8.0中,授權表使用InnoDB存儲引擎並且是事務性的。在MySQL 8.0之前,授權表使用MyISAM存儲引擎,並且是非事務性的。授予表存儲引擎的這一更改使帳戶管理語句(例如CREATE USER或GRANT)的行爲也可以隨之更改。以前,命名多個用戶的帳戶管理語句可能對某些用戶成功而對其他用戶失敗。現在,每個語句都是事務性的,並且對於所有指定的用戶都成功,或者回滾,如果發生任何錯誤,則無效。

每個授權表都包含作用域列和特權列:

  • 範圍列確定表中每一行的範圍;也就是說,該行適用的上下文。例如,具有“主機”和“用戶”值分別爲“ h1.example.net”和“ bob”的用戶錶行適用於驗證指定了bob用戶名的客戶端從主機h1.example.net與服務器建立的連接。同樣,當bob從主機h1.example.net連接以訪問報告數據庫時,將應用具有Host,User和Db列值分別爲’h1.example.net’,'bob’和’reports’的db錶行。table_priv和columns_priv表包含範圍列,這些範圍列指示每行適用的表或表/列組合。procs_priv作用域列指示每行適用的存儲例程。
  • 特權列指示錶行授予哪些特權;也就是說,它允許執行哪些操作。服務器將各種授權表中的信息組合在一起,以形成用戶權限的完整描述。

userdb授權表

Table Name user db
Scope columns Host Host
User Db
User
特權字段 Select_priv Select_priv
Insert_priv Insert_priv
Update_priv Update_priv
Delete_priv Delete_priv
Index_priv Index_priv
Alter_priv Alter_priv
Create_priv Create_priv
Drop_priv Drop_priv
Grant_priv Grant_priv
Create_view_priv Create_view_priv
Show_view_priv Show_view_priv
Create_routine_priv Create_routine_priv
Alter_routine_priv Alter_routine_priv
Execute_priv Execute_priv
Trigger_priv Trigger_priv
Event_priv Event_priv
Create_tmp_table_priv Create_tmp_table_priv
Lock_tables_priv Lock_tables_priv
References_priv References_priv
Reload_priv
Shutdown_priv
Process_priv
File_priv
Show_db_priv
Super_priv
Repl_slave_priv
Repl_client_priv
Create_user_priv
Create_tablespace_priv
Create_role_priv
Drop_role_priv
安全字段 ssl_type
ssl_cipher
x509_issuer
x509_subject
plugin
authentication_string
password_expired
password_last_changed
password_lifetime
account_locked
Password_reuse_history
Password_reuse_time
Password_require_current
User_attributes
資源控制字段 max_questions
max_updates
max_connections
max_user_connections

訪問控制

階段一:連接驗證

當客戶端嘗試連接到MySQL服務器時,服務器根據以下條件接受或拒絕連接:

  • 提供的的身份憑據以及是否可以通過提供正確的密碼來驗證身份
  • 賬戶是否已被鎖定

服務器首先檢查憑據,然後檢查帳戶鎖定狀態。任一步驟失敗都會導致服務器完全拒絕您的訪問。否則,服務器將接受連接,然後進入階段二並等待請求。

憑據校驗主要是通過校驗user表中的user,host,authentication_string三個字段,賬戶鎖定狀態存儲在user表中account_locked字段中。

使用三個用戶表作用域列(主機,用戶和認證字符串)執行憑據檢查。鎖定狀態記錄在用戶表account_locked列中。僅當某些用戶錶行中的“主機”和“用戶”列與客戶端主機名和用戶名匹配,客戶端提供該行中指定的密碼且account_locked值爲“ N”時,服務器才接受連接。僅當某些用戶錶行中的userhost字段與客戶端主機名和用戶名匹配,客戶端提供該行中指定的密碼且account_locked值爲N時,服務器才接受連接。

客戶端身份基於以下兩個信息:

  • 客戶端主機,即域名或IP地址
  • 用戶名,例如:root

如果user列的值是非空白的,則傳入連接中的用戶名必須完全匹配。如果user值爲空白,則它與任何用戶名匹配。如果與傳入連接匹配的用戶錶行的用戶名爲空,則該用戶將被視爲沒有名稱的匿名用戶,而不是具有客戶端實際指定的名稱的用戶。這意味着在連接持續時間內(即在第2階段),將使用空白用戶名進行所有進一步的訪問檢查。

user表中的非空白authentication_string值表示加密的密碼。MySQL不會將密碼存儲爲明文,任何人都可以看到。而是將嘗試連接的用戶提供的密碼進行加密(使用由帳戶身份驗證插件實現的密碼哈希方法)。然後在檢查密碼是否正確時在連接過程中使用加密的密碼。這樣就不會在連接上傳輸加密密碼。

mysql> select user, authentication_string from user where user = 'root' and host = '%';
+------+--------------------------------------------------------------------------------------------- ---------+
| user | authentication_string                                                                                                                         |
+------+-------------------------------------------------------------------------------------------------------+
| root | $A$005$%V,~wy({Nt{pt)1k?I,g6lMrrsej3UC5taF4V6/clkpGaYogHf7FIzwgijo3h9  |
+------+-------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

警告

從MySQL的角度來看,加密密碼是真實密碼,因此您絕不應該允許任何人訪問它。特別是,請勿授予非管理用戶對mysql系統數據庫中表的讀取權限。

下表顯示了user表中userhost的各種組合如何應用於傳入連接:

user host Permissible Connections
'fred' 'h1.example.net' fred只能從h1.example.net連接到服務器
'' 'h1.example.net' 任何用戶都可以從 h1.example.net連接
'fred' '%' fred可以從任何主機連接到服務器
'' '%' 任何用戶可以從任何主機連接到服務器
'fred' '%.example.net' fred可以從 example.net 域下任何主機連接
'fred' 'x.example.%' fred可以從x.example.*域名連接
'fred' '198.51.100.177' fred只能從IP地址 198.51.100.177連接服務器
'fred' '198.51.100.%' fred可以從198.51.100.*網段連接
'fred' '198.51.100.0/255.255.255.0' 等同於上一行

當客戶端傳入的身份憑據匹配多個條目時服務器必須確定要使用哪個匹配項。它可以按以下方式解決此問題:

  • 每當服務器將用戶表讀入內存時,它都會對行進行排序。
  • 客戶端嘗試連接時,服務器將按排序順序瀏覽各行。
  • 服務器使用與客戶端主機名和用戶名匹配的第一行。

服務器使用排序規則,該規則首先對具有最特定的主機值的行進行排序。主機名和IP地址是最具體的。(原義IP地址的特異性不受其是否具有網絡掩碼的影響,因此198.51.100.13198.51.100.0/255.255.255.0被認爲是同等具體的。)模式'%'表示“任何主機”,並且最少具體。空字符串""也表示“任何主機”,但在%之後排序。具有相同“主機”值的行將按照最特定的user值進行排序(空白的user值表示“任何用戶”,並且是最不特定的)。對於具有相同特定的userhost值的行,順序是不確定的。

要查看其工作原理,假設user表如下所示:

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

當服務器將表讀入內存時,它將使用剛剛描述的規則對行進行排序。排序後的結果如下所示:
在這裏插入圖片描述
當客戶端嘗試連接時,服務器將瀏覽已排序的行並使用找到的第一個匹配項。對於jeffreylocalhost的連接,表中的兩行匹配:hostuser值爲'localhost'''的那一行,以及hostuser值爲'%''jeffrey'的那一行。localhost行首先以排序順序出現,因此服務器會使用這行。

這是另一個例子。假設用戶表如下所示:
在這裏插入圖片描述
排序後的結果如下:
在這裏插入圖片描述
第一行匹配來自h1.example.netjeffrey連接,第二行匹配來自任何主機的jeffrey連接。

提示

常見的誤解是認爲,當客戶端從某個主機以用戶名密碼登錄時服務器會完全匹配其信息,這是不對的。前面的示例對此進行了說明,其中jeffreyh1.example.net的連接首先不匹配包含jeffrey
作爲user字段值的行,而是不匹配用戶名的行。結果,即使jeffrey在連接時指定了用戶名,他仍被認證爲匿名用戶

如果您能夠連接到服務器,但是特權不是您所期望的,則您可能已通過其他帳戶的身份驗證。要找出服務器用來驗證您身份的帳戶,請使用CURRENT_USER()函數。此函數會返回user_name@host_name格式返回一個值,該值指示匹配的用戶錶行中的userhost值。
在這裏插入圖片描述

階段二:請求驗證

建立連接後,服務器進入訪問控制的第二階段。對於通過該連接發出的每個請求,服務器將確定要執行的操作,然後檢查是否具有足夠的特權。這是授權表中的特權列起作用的地方。這些特權可以來自任何用戶,global_grantsdbtables_privcolumns_privprocs_priv表。

userglobal_grants表授予全局特權。這些表中給定帳戶的行表示無論默認數據庫是什麼,在全局基礎上應用的帳戶特權。例如,如果用戶表授予您DELETE特權,則可以從服務器主機上任何數據庫中的任何表中刪除行。明智的做法是僅將需要特權的用戶授予用戶表中的特權,例如數據庫管理員。對於其他用戶,請將用戶表中的所有特權都設置爲N,並僅在更特定的級別(對於特定的數據庫,表,列或例程)授予特權。也可以全局授予數據庫特權,但可以撤銷部分權限來限制它們在特定數據庫上的執行。
db表授予特定於數據庫的特權。該表的scope列中的值可以採用以下形式:

  • 空的用戶值與匿名用戶匹配。非空值從字面上匹配;用戶名中沒有通配符。
  • 通配符和可以在hostdb列中使用。這些具有與使用LIKE運算符執行的模式匹配操作相同的含義。如果要在授予特權時按字面使用任何一個字符,則必須使用反斜槓將其轉義。例如,要將下劃線字符(_)包括在數據庫名稱中,請在GRANT語句中將其指定爲\_
  • 或空白host值表示“任何主機”。
  • 或空白db值表示“任何數據庫”。

服務器將數據庫表讀入內存,並在讀取user表的同時對其進行排序。服務器根據hostdbuser列對數據庫表進行排序。與用戶表一樣,排序將最具體的值放在最前面,最不具體的值放在最後,當服務器尋找匹配的行時,它將使用找到的第一個匹配項。
服務器使用排序的表來驗證它收到的每個請求。對於需要管理特權(例如SHUTDOWNRELOAD)的請求,服務器僅檢查userglobal_privilege表,因爲它們是唯一指定管理特權的表。如果這些表中帳戶的行允許請求的操作,則服務器將授予訪問權限,否則拒絕訪問。例如,如果您想執行mysqladmin shutdown,但是您的用戶錶行未授予您SHUTDOWN特權,則服務器將拒絕訪問,甚至不檢查db表。(後一個表不包含Shutdown_priv列,因此無需檢查它。)

對於與數據庫相關的請求(INSERTUPDATE等),服務器首先在user錶行中檢查用戶的全局特權(減去部分撤銷所施加的任何特權限制)。如果該行允許請求的操作,則授予訪問權限。如果用戶表中的全局特權不足,則服務器從數據庫表中確定用戶的數據庫特定特權:

服務器在db表中查找hostdbuser列上的匹配項。hostuser列與連接用戶的主機名和MySQL用戶名匹配。db列與用戶要訪問的數據庫匹配。如果主機和用戶沒有行,則拒絕訪問。
在確定db錶行授予的特定於數據庫的特權之後,服務器會將它們添加到user表授予的全局特權中。如果結果允許請求的操作,則授予訪問權限。否則,服務器會先檢查tables_priv和columns_priv表中用戶的表特權和列特權,將這些特權添加到用戶特權中,然後根據結果允許或拒絕訪問。對於存儲過程操作,服務器使用procs_priv表而不是table_privcolumns_priv

前面關於如何計算用戶特權的描述可以總結如下:

global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges
OR routine privileges

上面介紹的請求權限驗證流程可能令人迷惑,如果最初發現全局特權不足以執行請求的操作,則服務器隨後會將這些特權添加到數據庫,表和列特權中。原因是請求可能需要一種以上的特權。例如,如果執行INSERT INTO ... SELECT語句,則需要INSERTSELECT特權。您的特權可能是這樣的:user錶行授予一個全局特權,而數據庫錶行授予另一個特權,專門針對相關數據庫。在這種情況下,您具有執行請求所必需的特權,但是服務器無法僅從全局特權或數據庫特權中分辨出這一點。它必須根據組合的權限做出訪問控制決定。

賬戶管理

創建賬戶並授權

CREATE USER 'finley'@'localhost'
  IDENTIFIED BY 'password';
GRANT ALL
  ON *.*
  TO 'finley'@'localhost'
  WITH GRANT OPTION;

CREATE USER 'finley'@'%.example.com'
  IDENTIFIED BY 'password';
GRANT ALL
  ON *.*
  TO 'finley'@'%.example.com'
  WITH GRANT OPTION;

CREATE USER 'admin'@'localhost'
  IDENTIFIED BY 'password';
GRANT RELOAD,PROCESS
  ON *.*
  TO 'admin'@'localhost';

CREATE USER 'dummy'@'localhost';

以上四組例子創建了四個賬戶,他們分別具有如下屬性:

  • 前兩個帳戶的用戶名均爲finley。兩者都是具有執行任何操作的完整全局特權的超級用戶帳戶。僅當從本地主機連接時,才能使用'finley' @'localhost'帳戶。'finley'@'%.example.com'帳戶在主機部分使用%通配符,因此可用於從example.com域名下的任何主機進行連接。

    如果有本地主機的匿名用戶帳戶,則必須使用'finley'@'localhost'帳戶。如果沒有'finley'@'localhost'帳戶,則當finley從本地主機進行連接並且finley被視爲匿名用戶時,該匿名用戶帳戶將具有優先權。原因是匿名用戶帳戶的主機列值比'finley'@'%'帳戶更具體,因此在用戶表排序順序中排在更早的位置。

  • 'admin' @'localhost'帳戶只能由admin用來從本地主機進行連接。它被授予全局RELOADPROCESS管理特權。這些特權使admin用戶可以執行mysqladmin reloadmysqladmin refreshmysqladmin flush-xxx命令以及mysqladmin processlist。不授予訪問任何數據庫的特權。您可以使用GRANT語句添加此類特權。

  • 'dummy'@'localhost'帳戶沒有密碼(不安全,不建議使用)。該帳戶只能用於從本地主機連接。這條語句沒有授予任何特權,您假定您將使用GRANT語句授予該帳戶特定的特權。

以上的授權語句中的權限名可在之前的MYSQL特權找到。

前面的示例在全局級別授予特權。下一個示例創建三個帳戶,並授予他們較低級別的訪問權限;即針對特定數據庫或數據庫中的對象。每個帳戶都有一個自定義用戶名,但是主機名部分有所不同:

CREATE USER 'custom'@'localhost'
  IDENTIFIED BY 'password';
GRANT ALL
  ON bankaccount.*
  TO 'custom'@'localhost';

CREATE USER 'custom'@'host47.example.com'
  IDENTIFIED BY 'password';
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
  ON expenses.*
  TO 'custom'@'host47.example.com';

CREATE USER 'custom'@'%.example.com'
  IDENTIFIED BY 'password';
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
  ON customer.addresses
  TO 'custom'@'%.example.com';

這三個帳戶適合在以下情況使用:

  • 'custom'@'localhost'帳戶具有訪問bankaccount數據庫的所有數據庫級特權。該帳戶只能用於從本地主機連接到服務器。

  • 'custom'@'host47.example.com'帳戶具有訪問expenses數據庫的特定數據庫級別特權。該帳戶只能用於從主機host47.example.com連接到服務器。

  • 'custom'@'%.example.com'帳戶具有特定的表級特權,可以從example.com域名下的任何主機訪問客戶數據庫中的地址表。由於在帳戶名稱的主機部分中使用通配符,因此該帳戶可用於從此域名中的所有計算機連接到服務器。

檢查帳戶特權和屬性

使用SHOW GRANTS查看帳戶的特權:

mysql> SHOW GRANTS FOR 'admin'@'localhost';
+----------------------------------------------------------------------------+
| Grants for admin@localhost                                                            |
+----------------------------------------------------------------------------+
| GRANT RELOAD, PROCESS ON *.* TO 'admin'@'localhost' |
+----------------------------------------------------------------------------+

使用SHOW CREATE USER查看帳戶的非特權屬性:

mysql> SET print_identified_with_as_hex = ON;    ''' 賬戶信息以十六進制打印,保護隱私
mysql> SHOW CREATE USER 'admin'@'localhost'\G
*************************** 1. row ***************************
CREATE USER for admin@localhost: CREATE USER 'admin'@'localhost'
IDENTIFIED WITH 'caching_sha2_password'
AS 0x24412430303524301D0E17054E2241362B1419313C3E44326F294133734B30792F436E77764270373039612E32445250786D43594F45354532324B6169794F47457852796E32
REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
PASSWORD HISTORY DEFAULT
PASSWORD REUSE INTERVAL DEFAULT
PASSWORD REQUIRE CURRENT DEFAULT

啓用print_identified_with_as_hex系統變量(自MySQL 8.0.17起可用)會導致SHOW CREATE USER以十六進制字符串而非常規字符串文字形式顯示包含不可打印字符的哈希值。

撤銷帳戶特權

要撤消帳戶特權,請使用REVOKE語句。可以在不同級別撤銷特權,就像可以在不同級別授予特權一樣。

撤銷全局特權:

REVOKE ALL
  ON *.*
  FROM 'finley'@'%.example.com';

REVOKE RELOAD
  ON *.*
  FROM 'admin'@'localhost';

撤消數據庫級特權:

REVOKE CREATE,DROP
  ON expenses.*
  FROM 'custom'@'host47.example.com';

撤消表級特權:

REVOKE INSERT,UPDATE,DELETE
  ON customer.addresses
  FROM 'custom'@'%.example.com';

要檢查特權撤銷的效果,請使用SHOW GRANTS

mysql> SHOW GRANTS FOR 'admin'@'localhost';
+----------------------------------------------------------------+
| Grants for admin@localhost                                          |
+----------------------------------------------------------------+
| GRANT PROCESS ON *.* TO 'admin'@'localhost'  |
+----------------------------------------------------------------+

刪除帳戶

要刪除帳戶,請使用DROP USER語句。例如,刪除一些先前創建的帳戶:

DROP USER 'finley'@'localhost';
DROP USER 'finley'@'%.example.com';
DROP USER 'admin'@'localhost';
DROP USER 'dummy'@'localhost';

保留賬戶

官方文檔

在數據目錄初始化期間,MySQL創建應被視爲保留的用戶帳戶。

當剛安裝完MYSQL後,會創建以下用戶:
在這裏插入圖片描述

  • 'root'@'localhost:用於管理目的。該帳戶具有所有特權,是系統帳戶,並且可以執行任何操作。

    嚴格來說,此帳戶名不是保留的,在某種意義上說,某些安裝會將根帳戶重命名爲其他名稱,以避免暴露具有衆所周知名稱的高特權帳戶。

  • 'mysql.sys'@'localhost':用作sys模式對象的DEFINER。使用mysql.sys帳戶可避免DBA重命名或刪除根帳戶時發生的問題。此帳戶已鎖定,因此不能用於客戶端連接。

  • 'mysql.session'@'localhost':插件在內部用於訪問服務器。此帳戶已鎖定,因此不能用於客戶端連接。該帳戶是系統帳戶。

  • 'mysql.infoschema'@'localhost':用作INFORMATION_SCHEMA視圖的DEFINERmysql.infoschema帳戶的使用避免了DBA重命名或刪除根帳戶時發生的問題。此帳戶已鎖定,因此不能用於客戶端連接。

分配賬戶密碼

官方密碼

MySQL將憑據存儲在mysql系統數據庫的user表中。分配或修改密碼的操作僅允許具有CREATE USER特權或mysql數據庫特權(創建新帳戶的INSERT特權,修改現有帳戶的UPDATE特權)的用戶使用。如果啓用了read_only系統變量,則使用帳戶修改語句(例如CREATE USERALTER USER)還需要CONNECTION_ADMIN特權(或不建議使用的SUPER特權)。

此處的討論僅彙總了最常見的密碼分配語句的語法。

創建用戶

要在創建新帳戶時分配密碼,請使用CREATE USER幷包含IDENTIFIED BY子句:

CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'password';

CREATE USER還支持用於指定帳戶身份驗證插件的語法。具體參看官方文檔

修改密碼

要爲現有帳戶分配或更改密碼,請使用帶有IDENTIFIED BY子句的ALTER USER語句:

ALTER USER 'jeffrey'@'localhost' IDENTIFIED BY 'password';

如果不是以匿名用戶身份連接的,則可以更改自己的密碼,而無需直接指定自己的帳戶:

ALTER USER USER() IDENTIFIED BY 'password';

要從命令行更改帳戶密碼,請使用mysqladmin命令:

mysqladmin -u user_name -h host_name password "password"

此命令設置密碼的帳戶是mysql.user系統表中帶有一行的帳戶,該行與user字段中的user_name和host列中連接的客戶端主機相匹配。

警告使用mysqladmin設置密碼應該被認爲是不安全的。在某些系統上,密碼對系統狀態程序(例如ps命令)可見,其他用戶可能會調用該密碼來顯示命令行。MySQL客戶端通常在初始化序列期間用零覆蓋命令行密碼參數。但是,仍然有一個短暫的時間間隔,在該時間間隔內該值是可見的。同樣,在某些系統上,此覆蓋策略無效,並且ps仍然可以看到密碼。(SystemV Unix系統以及其他系統可能會遇到此問題。)

密碼管理

MySQL支持以下密碼管理功能:

  • 密碼到期,要求定期更改密碼。
  • 密碼重用限制,以防止再次選擇舊密碼。
  • 密碼驗證,要求更改密碼還指定要替換的當前密碼。
  • 雙密碼,使客戶端可以使用主密碼或輔助密碼進行連接。
  • 密碼強度評估,要求使用強密碼。
  • 隨機密碼生成,作爲要求管理員指定明確的文字密碼的替代方法。
  • 密碼失敗跟蹤,用於在連續多次錯誤密碼登錄失敗後啓用臨時帳戶鎖定。

以下各節描述了這些功能,但密碼強度評估功能除外,後者是使用validate_password組件實現的,在這之前筆者已將這個組件卸載了。

重要MySQL使用mysql系統數據庫中的表實現密碼管理功能。如果從早期版本升級MySQL,則系統表可能不是最新的。在這種情況下,服務器會在啓動過程中將類似於以下消息的消息寫入錯誤日誌(確切的數目可能有所不同):

[ERROR] Column count of mysql.user is wrong. Expected 49, found 47. The table is probably corrupted
[Warning] ACL table mysql.password_history missing. Some operations may fail.

要解決此問題,請執行MySQL升級過程。請參見升級MySQL。在此之前,無法更改密碼。

內部與外部憑證存儲

一些身份驗證插件在mysql.user系統表中將帳戶憑據存儲在MySQL內部:

  • mysql_native_password
  • caching_sha2_password
  • sha256_password

本節中的大多數討論都適用於此類身份驗證插件,因爲此處描述的大多數密碼管理功能都是基於MySQL本身處理的內部憑據存儲。其他身份驗證插件將帳戶憑據存儲在MySQL的外部。對於使用插件針對外部憑據系統執行身份驗證的帳戶,密碼管理也必須在外部針對該系統進行處理。

唯一的例外是登錄失敗跟蹤和臨時帳戶鎖定的選項適用於所有帳戶,而不僅限於使用內部憑據存儲的帳戶,因爲MySQL能夠評估任何帳戶的登錄嘗試狀態,無論它是使用內部帳戶還是內部帳戶。外部憑證存儲。

密碼過期策略

MySQL使數據庫管理員可以手動使帳戶密碼過期,並建立自動密碼過期策略。可以在全局範圍內建立到期策略,並且可以將各個帳戶設置爲遵從全局策略,或者以特定的每個帳戶行爲覆蓋全局策略。
要手動使帳戶密碼失效,請使用ALTER USER語句:

ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE;

該操作在mysql.user系統表的相應行中標記密碼已過期。

根據策略,密碼有效期是自動的,並且基於密碼有效期,對於給定帳戶,將從最近一次密碼更改的日期和時間開始對其進行評估。mysql.user系統表爲每個帳戶指示上次更改密碼的時間,如果服務器的使用期限大於允許的使用期限,則服務器會在客戶端連接時自動將其視爲過期密碼。此方法無需明確的手動密碼有效期。

要全局建立自動密碼過期策略,請使用default_password_lifetime系統變量。其默認值爲0,這將禁用自動密碼過期。如果default_password_lifetime的值爲正整數N,則表示允許的密碼生存期,因此必須每N天更改一次密碼。

示例:

  • 要建立密碼有效期約爲六個月的全局策略,請在服務器my.cnf文件中的以下行啓動服務器:

    [mysqld]
    default_password_lifetime=180
    
  • 要建立密碼永不過期的全局策略,請將default_password_lifetime設置爲0:

    [mysqld]
    default_password_lifetime=0
    
  • 還可以在運行時設置default_password_lifetime並將其持久化:

    SET PERSIST default_password_lifetime = 180;
    SET PERSIST default_password_lifetime = 0;
    

    SET PERSIST設置正在運行的MySQL實例的值。它還保存該值以繼續進行後續服務器重新啓動。要更改正在運行的MySQL實例的值而不使它繼續進行後續的重新啓動,請使用GLOBAL關鍵字而不是PERSIST

全局密碼過期策略適用於尚未設置爲覆蓋該策略的所有帳戶。要爲單個帳戶建立策略,請使用CREATE USERALTER USER語句的PASSWORD EXPIRE選項。

一個對賬單示例

  • 要求每90天更改一次密碼:

    CREATE USER 'jeffrey'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;
    ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;
    

    該到期選項將覆蓋該語句命名的所有帳戶的全局策略。

  • 禁用密碼有效期:

    CREATE USER 'jeffrey'@'localhost' PASSWORD EXPIRE NEVER;
    ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE NEVER;
    

    該到期選項將覆蓋該語句命名的所有帳戶的全局策略。

  • 對語句命名的所有帳戶遵循全局到期策略:

    CREATE USER 'jeffrey'@'localhost' PASSWORD EXPIRE DEFAULT;
    ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE DEFAULT;
    

客戶端成功連接後,服務器將確定帳戶密碼是否已過期:

  • 服務器檢查密碼是否已手動過期。
  • 否則,服務器會根據自動密碼過期策略檢查密碼使用期限是否大於其允許的使用期限。如果是這樣,則服務器認爲密碼已過期。

如果密碼已過期(無論是手動還是自動),則服務器將斷開客戶端連接或限制其允許的操作。受限制的客戶端執行的操作會導致錯誤,直到用戶建立新的帳戶密碼爲止:

mysql> SELECT 1;
ERROR 1820 (HY000): You must reset your password using ALTER USER
statement before executing this statement.

mysql> ALTER USER USER() IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

客戶端重置密碼後,服務器將恢復會話以及使用該帳戶的後續連接的正常訪問。管理員用戶也可以重設帳戶密碼,但是該帳戶的所有現有受限會話仍然受到限制。使用該帳戶的客戶端必須斷開連接並重新連接,然後語句才能成功執行。

提示
注意儘管可以通過將過期的密碼設置爲當前值來“重置”它,但出於良好的政策考慮,最好選擇其他密碼。DBA可以通過建立適當的密碼重用策略來強制不重用。請參閱密碼重用策略

密碼重用策略

MySQL允許對重用以前的密碼進行限制。可以根據密碼更改的次數,經過的時間或同時基於兩者來建立重用限制。可以在全局範圍內建立重用策略,並且可以將各個帳戶設置爲遵從全局策略,或者使用特定的按帳戶行爲替換全局策略。

帳戶的密碼歷史記錄由過去分配的密碼組成。MySQL可以限制從以下歷史記錄中選擇新密碼:

  • 如果根據密碼更改次數限制了帳戶,則無法從指定數量的最新密碼中選擇新密碼。例如,如果密碼更改的最小次數設置爲3,則新密碼不能與最新的3個密碼相同。

  • 如果根據時間限制了帳戶,則無法從歷史記錄中指定天數以上的密碼中選擇新密碼。例如,如果密碼重用間隔設置爲60,則新密碼一定不能屬於過去60天內先前選擇的密碼。

提示
空密碼不計入密碼歷史記錄,並且隨時可以重複使用。

要全局建立密碼重用策略,請使用password_historypassword_reuse_interval系統變量。

示例

  • 要禁止重複使用最後6個密碼或比365天新的密碼,請在服務器my.cnf文件中添加以下行:

    [mysqld]
    password_history=6
    password_reuse_interval=365
    
  • 要在運行時設置和保留變量,請使用如下語句:

    SET PERSIST password_history = 6;
    SET PERSIST password_reuse_interval = 365;
    

    SET PERSIST設置正在運行的MySQL實例的值。它還保存該值以繼續進行後續服務器重新啓動。要更改正在運行的MySQL實例的值而不使它繼續進行後續的重新啓動,請使用GLOBAL關鍵字而不是PERSIST

一個對賬單示例

  • 在允許重複使用之前,至少需要更改5次密碼:

    CREATE USER 'jeffrey'@'localhost' PASSWORD HISTORY 5;
    ALTER USER 'jeffrey'@'localhost' PASSWORD HISTORY 5;
    

    此歷史記錄長度選項將覆蓋該語句命名的所有帳戶的全局策略。

  • 至少需要經過365天,才能允許重複使用:

    CREATE USER 'jeffrey'@'localhost' PASSWORD REUSE INTERVAL 365 DAY;
    ALTER USER 'jeffrey'@'localhost' PASSWORD REUSE INTERVAL 365 DAY;
    

    這個“過去時間”的選項會覆蓋該語句命名的所有帳戶的全局策略。

  • 要結合兩種類型的重用限制,請一起使用PASSWORD HISTORYPASSWORD REUSE INTERVAL

    CREATE USER 'jeffrey'@'localhost'
      PASSWORD HISTORY 5
      PASSWORD REUSE INTERVAL 365 DAY;
    ALTER USER 'jeffrey'@'localhost'
      PASSWORD HISTORY 5
      PASSWORD REUSE INTERVAL 365 DAY;
    

    這些選項覆蓋了該語句命名的所有帳戶的全局策略重用限制。

  • 對於這兩種類型的重用限制,請遵循全局策略:

    CREATE USER 'jeffrey'@'localhost'
      PASSWORD HISTORY DEFAULT
      PASSWORD REUSE INTERVAL DEFAULT;
    ALTER USER 'jeffrey'@'localhost'
      PASSWORD HISTORY DEFAULT
    PASSWORD REUSE INTERVAL DEFAULT;
    

密碼驗證要求策略

從MySQL 8.0.13開始,可能需要通過指定要替換的當前密碼來驗證更改帳戶密碼的嘗試。這使DBA可以防止用戶在不證明他們知道當前密碼的情況下更改密碼。否則,例如,如果一個用戶暫時退出終端會話而沒有註銷,並且惡意用戶使用該會話來更改原始用戶的MySQL密碼,則可能會發生此類更改。這可能會帶來不幸的後果:

  • 在管理員重置帳戶密碼之前,原始用戶將無法訪問MySQL。
  • 在密碼重置發生之前,惡意用戶可以使用良性用戶更改的憑據訪問MySQL。

可以在全局範圍內建立密碼驗證策略,並且可以將各個帳戶設置爲遵從全局策略,或者使用特定的按帳戶行爲覆蓋全局策略。
對於每個帳戶,其mysql.user行指示是否存在特定於帳戶的設置,要求對當前密碼進行驗證以進行密碼更改嘗試。該設置由CREATE USERALTER USER語句的PASSWORD REQUIRE選項建立:

  • 如果帳戶設置爲PASSWORD REQUIRE CURRENT,則密碼更改必須指定當前密碼。

  • 如果帳戶設置爲PASSWORD REQUIRE CURRENT OPTIONAL,則可以更改密碼,但不必指定當前密碼。

  • 如果帳戶設置爲PASSWORD REQUIRE CURRENT DEFAULT,則password_require_current系統變量將確定該帳戶的驗證所需策略:

    • 如果啓用了password_require_current,則密碼更改必須指定當前密碼。
    • 如果禁用password_require_current,則可以但不必指定當前密碼來更改密碼。

換句話說,如果帳戶設置不是PASSWORD REQUIRE CURRENT DEFAULT,則帳戶設置優先於password_require_current系統變量建立的全局策略。否則,該帳戶將遵循password_require_current設置。

默認情況下,密碼驗證是可選的:password_require_current被禁用,並且沒有PASSWORD REQUIRE選項創建的帳戶默認爲PASSWORD REQUIRE CURRENT DEFAULT

下表顯示了每個帳戶設置如何與password_require_current系統變量值進行交互,以確定需要帳戶密碼驗證的策略。

密碼驗證策略

每個賬戶的設置 password_require_current 系統變量 修改密碼前是否需要確認原密碼
PASSWORD REQUIRE CURRENT OFF Yes
PASSWORD REQUIRE CURRENT ON Yes
PASSWORD REQUIRE CURRENT OPTIONAL OFF No
PASSWORD REQUIRE CURRENT OPTIONAL ON No
PASSWORD REQUIRE CURRENT DEFAULT OFF No
PASSWORD REQUIRE CURRENT DEFAULT ON Yes

注意
特權用戶可以在不指定當前密碼的情況下更改任何帳戶密碼,而不管驗證要求的策略如何。特權用戶是具有mysql系統數據庫的全局CREATE USER特權或UPDATE特權的用戶。

要全局建立密碼驗證策略,請使用password_require_current系統變量。其默認值爲OFF,因此不需要更改帳戶密碼來指定當前密碼。
示例:

  • 要建立密碼更改必須指定當前密碼的全局策略,請在服務器my.cnf文件中使用以下幾行啓動服務器:

    [mysqld]
    password_require_current=ON
    
  • 要在運行時設置和保留password_require_current,請使用以下語句之一:

    SET PERSIST password_require_current = ON;
    SET PERSIST password_require_current = OFF;
    

    SET PERSIST設置正在運行的MySQL實例的值。它還保存該值以繼續進行後續服務器重新啓動。要更改正在運行的MySQL實例的值而不使它繼續進行後續的重新啓動,請使用GLOBAL關鍵字而不是PERSIST

要求全局密碼驗證的策略適用於尚未設置爲覆蓋該策略的所有帳戶。要爲單個帳戶建立策略,請使用CREATE USERALTER USER語句的PASSWORD REQUIRE選項。

一個對賬單示例

  • 要求密碼更改指定當前密碼:

    CREATE USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT;
    ALTER USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT;
    

    該驗證選項將覆蓋該語句命名的所有帳戶的全局策略。

  • 不需要更改密碼指定當前密碼(可以但不必提供當前密碼):

    CREATE USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT OPTIONAL;
    ALTER USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT OPTIONAL;
    

    當用戶使用ALTER USERSET PASSWORD語句更改密碼時,對當前密碼進行驗證。這些示例使用ALTER USER,這比SET PASSWORD更爲可取,但是這裏描述的原理對於兩個語句都是相同的。

  • 對語句命名的所有帳戶都遵循全局密碼驗證所需的策略:

    CREATE USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT DEFAULT;
    ALTER USER 'jeffrey'@'localhost' PASSWORD REQUIRE CURRENT DEFAULT;
    

當用戶使用ALTER USERSET PASSWORD語句更改密碼時,對當前密碼進行驗證。這些示例使用ALTER USER,這比SET PASSWORD更爲可取,但是這裏描述的原理對於兩個語句都是相同的。

在更改密碼的語句中,REPLACE子句指定要替換的當前密碼。

示例

  • 更改當前用戶的密碼:

    ALTER USER USER() IDENTIFIED BY 'auth_string' REPLACE 'current_auth_string';
    
  • 更改指定用戶的密碼:

    ALTER USER 'jeffrey'@'localhost'
      IDENTIFIED BY 'auth_string'
      REPLACE 'current_auth_string';
    
  • 更改命名用戶的身份驗證插件和密碼:

    ALTER USER 'jeffrey'@'localhost'
      IDENTIFIED WITH caching_sha2_password BY 'auth_string'
      REPLACE 'current_auth_string';
    

REPLACE子句的工作方式如下:

  • 如果需要更改帳戶密碼以指定當前密碼,則必須給出REPLACE,以驗證嘗試進行更改的用戶實際上知道當前密碼。

  • 如果可以(但不必指定當前密碼)更改帳戶密碼,則REPLACE是可選的。

  • 如果指定了REPLACE,則必須指定正確的當前密碼,否則會發生錯誤。

  • 即使REPLACE是可選的,也是如此。

  • 僅當更改當前用戶的帳戶密碼時才能指定REPLACE。(這意味着在剛剛顯示的示例中,除非當前用戶爲jeffrey,否則顯式命名jeffrey帳戶的語句將失敗。)即使特權用戶嘗試對另一個用戶進行更改,也是如此。但是,這樣的用戶可以在不指定REPLACE的情況下更改任何密碼。

  • 二進制日誌中省略了REPLACE,以避免向其寫入明文密碼。

雙密碼支持

從MySQL 8.0.14開始,允許用戶帳戶具有雙重密碼,分別指定爲主要和次要密碼。雙密碼功能使在以下情況下無縫執行憑據更改成爲可能:

  • 系統具有大量的MySQL服務器,可能涉及複製。
  • 多個應用程序連接到不同的MySQL服務器。
  • 必須對應用程序用來連接到服務器的一個或多個帳戶進行定期的憑據更改。

考慮僅在一個帳戶只允許使用一個密碼的情況下,在上述類型的方案中必須如何執行憑證更改。在這種情況下,在更改帳戶密碼並將其傳播到所有服務器以及何時更新所有使用該帳戶的應用程序以使用新密碼的時間上,必須緊密合作。此過程可能涉及服務器或應用程序不可用的停機時間。

使用雙重密碼,可以更容易地,分階段地更輕鬆地進行憑據更改,而無需密切合作,也無需停機:

  1. 對於每個受影響的帳戶,在服務器上建立新的主密碼,並保留當前密碼作爲輔助密碼。這使服務器能夠識別每個帳戶的主密碼或輔助密碼,而應用程序可以繼續使用與以前相同的密碼(現在稱爲輔助密碼)連接到服務器。
  2. 密碼更改傳播到所有服務器後,修改使用任何受影響帳戶的應用程序以使用帳戶主密碼進行連接。
  3. 將所有應用程序從輔助密碼遷移到主要密碼後,不再需要輔助密碼,可以將其丟棄。此更改傳播到所有服務器後,只能使用每個帳戶的主密碼進行連接。憑據更改現已完成。

MySQL通過保存和丟棄輔助密碼的語法實現了雙密碼功能:

  • 當您分配新的主要密碼時,ALTER USERSET PASSWORD語句的RETAIN CURRENT PASSWORD子句會將帳戶當前密碼保存爲其次要密碼。

  • ALTER USERDISCARD OLD PASSWORD子句將丟棄帳戶的輔助密碼,僅保留主密碼。

假設對於先前描述的憑據更改方案,應用程序使用名爲appuser1@ host1.example.com的帳戶連接到服務器,並且該帳戶的密碼將從password_a更改爲password_b

要執行此憑據更改,請按以下方式使用ALTER USER

  1. 在不是備份從節點的每個服務器上,將password_b設置爲新的appuser1主密碼,並保留當前密碼作爲輔助密碼:

    ALTER USER 'appuser1'@'host1.example.com'
      IDENTIFIED BY 'password_b'
      RETAIN CURRENT PASSWORD;
    
  2. 等待密碼更改,以將整個系統複製到所有從屬服務器。

  3. 修改使用appuser1帳戶的每個應用程序,以使其使用password_b而不是password_a的密碼連接到服務器。

  4. 此時,不再需要輔助密碼。在不是複製從服務器的每個服務器上,放棄輔助密碼:

    ALTER USER 'appuser1'@'host1.example.com'
      DISCARD OLD PASSWORD;
    
  5. 丟棄密碼更改複製到所有從屬服務器後,憑據更改完成。

RETAIN CURRENT PASSWORDDISCARD OLD PASSWORD子句具有以下效果:

  • RETAIN CURRENT PASSWORD保留帳戶當前密碼作爲其次要密碼,以替換任何現有的次要密碼。新密碼成爲主密碼,但是客戶端可以使用主密碼或輔助密碼使用該帳戶連接到服務器。(例外:如果ALTER USERSET PASSWORD語句指定的新密碼爲空,則即使給出了RETAIN CURRENT PASSWORD,二級密碼也將爲空。)

  • 如果爲具有空主密碼的帳戶指定RETAIN CURRENT PASSWORD,則該語句將失敗。

  • 如果帳戶具有輔助密碼,而您在未指定RETAIN CURRENT PASSWORD的情況下更改了其主密碼,則輔助密碼將保持不變。

  • 對於ALTER USER,如果您更改分配給該帳戶的身份驗證插件,則輔助密碼將被丟棄。如果您更改身份驗證插件,並且還指定了RETAIN CURRENT PASSWORD,則該語句將失敗。

  • 對於ALTER USERDISCARD OLD PASSWORD會丟棄輔助密碼(如果存在)。該帳戶僅保留其主密碼,並且客戶端只能使用該主密碼來使用該帳戶連接到服務器。

修改輔助密碼的語句需要以下特權:

  • 要對適用於您自己的帳戶的ALTER USERSET PASSWORD語句使用RETAIN CURRENT PASSWORDDISCARD OLD PASSWORD子句,必須具有APPLICATION_PASSWORD_ADMIN特權。由於大多數用戶僅需要一個密碼,因此需要特權來操作您自己的輔助密碼。

  • 如果允許一個帳戶操作所有帳戶的輔助密碼,則應授予該帳戶CREATE USER特權,而不是APPLICATION_PASSWORD_ADMIN

隨機密碼生成

從MySQL 8.0.18開始,CREATE USERALTER USERSET PASSWORD語句具有爲用戶帳戶生成隨機密碼的功能,可以替代要求管理員指定的文字密碼的替代方法。本節描述了生成隨機密碼的共同特徵。

默認情況下,生成的隨機密碼的長度爲20個字符。該長度由generate_random_password_length系統變量控制,範圍爲5到255。

對於每個爲其語句生成隨機密碼的帳戶,該語句將密碼存儲在mysql.user系統表中,該密碼已針對帳戶身份驗證插件進行了適當的哈希處理。該語句還在結果集的一行中返回明文密碼,以使其對執行該語句的用戶或應用程序可用。結果集列被命名爲用戶,主機和生成的密碼,指示標識mysql.user系統表中受影響行的用戶名和主機名值,以及明文生成的密碼。

mysql> CREATE USER
       'u1'@'localhost' IDENTIFIED BY RANDOM PASSWORD,
       'u2'@'%.example.com' IDENTIFIED BY RANDOM PASSWORD,
       'u3'@'%.org' IDENTIFIED BY RANDOM PASSWORD;
+------+---------------+------------------------+
| user | host          | generated password     |
+------+----------------------+-----------------+
| u1   | localhost     | BA;42VpXqQ@i+y{&TDFF   |
| u2   | %.example.com | YX5>XRAJRP@>sn9azmD4   |
| u3   | %.org         | ;GfD44l,)C}PI/6)4TwZ   |
+------+---------------+------------------------+
mysql> ALTER USER
       'u1'@'localhost' IDENTIFIED BY RANDOM PASSWORD,
       'u2'@'%.example.com' IDENTIFIED BY RANDOM PASSWORD;
+------+---------------+----------------------+
| user | host          | generated password   |
+------+---------------------+----------------+
| u1   | localhost     | yhXBrBp.;Y6abB)e_UWr |
| u2   | %.example.com | >M-vmjp9DTY6}hkp,RcC |
+------+---------------+----------------------+
mysql> SET PASSWORD FOR 'u3'@'%.org' TO RANDOM;
+------+-------+-----------------------+
| user | host  | generated password    |
+------+-------+-----------------------+
| u3   | %.org | o(._oNn)d;FC<vJIDg9M  |
+------+-------+-----------------------+

CREATE USERALTER USERSET PASSWORD語句生成一個帳戶的隨機密碼,並以IDENTIFIED WITH auth_plugin AS'auth_string'子句作爲CREATE USERALTER USER語句寫入二進制日誌中,其中auth_plugin是帳戶身份驗證插件,auth_string是帳戶的哈希密碼值。

如果安裝了validate_password組件,則它實施的策略對生成的密碼無效。(密碼驗證的目的是幫助人們創建更好的密碼。)

登錄失敗跟蹤和臨時帳戶鎖定

從MySQL 8.0.19開始,管理員可以配置用戶帳戶,以便太多連續登錄失敗會導致臨時帳戶鎖定。

在這種情況下,“登錄失敗”表示客戶端在連接嘗試期間無法提供正確的密碼。它不包括由於未知用戶或網絡問題等原因導致的連接失敗。對於具有雙重密碼的帳戶(請參閱雙重密碼支持),兩個帳戶密碼均視爲正確。

可以使用CREATE USERALTER USER語句的FAILED_LOGIN_ATTEMPTSPASSWORD_LOCK_TIME選項對每個帳戶配置所需的登錄失敗次數和鎖定時間。

示例:

CREATE USER 'u1'@'localhost' IDENTIFIED BY 'password'
  FAILED_LOGIN_ATTEMPTS 3 PASSWORD_LOCK_TIME 3;

ALTER USER 'u2'@'localhost'
  FAILED_LOGIN_ATTEMPTS 4 PASSWORD_LOCK_TIME UNBOUNDED;

當發生太多連續登錄失敗時,客戶端會收到如下錯誤:

ERROR 3957 (HY000): Access denied for user user.
Account is blocked for D day(s) (R day(s) remaining)
due to N consecutive failed logins.

使用以下選項:

  • FAILED_LOGIN_ATTEMPTS N

    此選項指示是否跟蹤指定錯誤密碼的帳戶登錄嘗試。數字*N*指定有多少連續的錯誤密碼導致臨時帳戶鎖定。

  • PASSWORD_LOCK_TIME {N | UNBOUNDED}

    此選項指示在連續多次登錄嘗試後提供密碼錯誤後鎖定帳戶的時間。該值是數字*N*,用於指定帳戶保持鎖定的天數,或者是UNBOUNDED,用於指定當帳戶進入臨時鎖定狀態時,該狀態的持續時間不受限制,並且直到帳戶解鎖後才結束。解鎖的條件將在後面描述。

每個選項的*N*允許值範圍是0到32767。值爲0將禁用該選項。

登錄失敗跟蹤和臨時帳戶鎖定具有以下特徵:

  • 爲了使帳戶能夠進行失敗登錄跟蹤和臨時鎖定,其FAILED_LOGIN_ATTEMPTSPASSWORD_LOCK_TIME選項都必須爲非零。

  • 對於CREATE USER,如果未指定FAILED_LOGIN_ATTEMPTSPASSWORD_LOCK_TIME,則對於該語句命名的所有帳戶,其隱式默認值爲0。這意味着將禁用登錄失敗跟蹤和臨時帳戶鎖定。(這些隱式默認值也適用於引入失敗登錄跟蹤之前創建的帳戶。)

  • 對於ALTER USER,如果未指定FAILED_LOGIN_ATTEMPTSPASSWORD_LOCK_TIME,則對於該語句命名的所有帳戶,其值均保持不變。

  • 爲了使臨時帳戶鎖定,密碼失敗必須是連續的。在達到失敗登錄的FAILED_LOGIN_ATTEMPTS值之前發生的任何成功登錄都會導致失敗計數重置。例如,如果FAILED_LOGIN_ATTEMPTS爲4,並且發生了三個連續的密碼失敗,則必須再出現一個失敗才能開始鎖定。但是,如果下一次登錄成功,則將重置該帳戶的失敗登錄計數,以便再次需要四個連續的失敗來鎖定。

  • 一旦開始臨時鎖定,即使使用了正確的密碼,也無法成功登錄,直到鎖定持續時間過去或通過以下討論中列出的一種帳戶重置方法將帳戶解鎖。

當服務器讀取授權表時,它將初始化每個帳戶的狀態信息,其中包括是否啓用了失敗登錄跟蹤,該帳戶當前是否被臨時鎖定以及是否已開始鎖定(如果已啓用)以及該帳戶發生臨時鎖定之前的失敗次數未鎖定。

  • 在以下任何一種情況下,都會對所有帳戶進行全局重置:

    • 服務器重新啓動。
    • 執行FLUSH PRIVILEGES。(使用--skip-grant-tables啓動服務器會導致無法讀取授權表,這會禁用失敗登錄跟蹤。在這種情況下,首次執行FLUSH PRIVILEGES會導致服務器讀取授權表並啓用失敗-登錄跟蹤,以及重置所有帳戶。)
  • 在以下任何一種情況下都會發生按帳戶重置的情況:

    • 成功登錄該帳戶。
    • 鎖定持續時間過去了。在這種情況下,登錄失敗計數將在下次嘗試登錄時重置。
    • 爲該帳戶執行將FAILED_LOGIN_ATTEMPTSPASSWORD_LOCK_TIME(或兩者)設置爲任何值(包括當前選項值)的帳戶,或對該帳戶執行ALTER USER ... UNLOCK語句。

    該帳戶的其他ALTER USER語句對其當前的失敗登錄計數或鎖定狀態沒有影響。

登錄失敗跟蹤與用於檢查憑據的登錄帳戶相關聯。如果正在使用用戶代理,則會對代理用戶(而不是被代理用戶)進行跟蹤。也就是說,跟蹤綁定到USER()指示的帳戶,而不是CURRENT_USER()指示的帳戶。有關代理和代理用戶之間區別的信息。

賬戶鎖定

MySQL支持對CREATE USERALTER USER語句使用ACCOUNT LOCKACCOUNT UNLOCK子句來鎖定和解鎖用戶帳戶:

  • CREATE USER一起使用時,這些子句指定新帳戶的初始鎖定狀態。在沒有任何一個子句的情況下,將以解鎖狀態創建帳戶。
  • 如果啓用validate_password組件,則即使該帳戶已鎖定,也將不允許創建沒有密碼的帳戶。

從MySQL 8.0.19開始,ALTER USER ... UNLOCK解鎖由於登錄失敗而被臨時鎖定的語句命名的任何帳戶。

帳戶鎖定狀態記錄在mysql.user系統表的account_locked列中。SHOW CREATE USER的輸出指示帳戶是鎖定還是未鎖定。

如果客戶端嘗試連接到鎖定的帳戶,則嘗試將失敗。服務器遞增Locked_connects狀態變量,該變量指示嘗試連接到鎖定帳戶的次數,返回ER_ACCOUNT_HAS_BEEN_LOCKED錯誤,並將消息寫入錯誤日誌:

Access denied for user 'user_name'@'host_name'.
Account is locked.

鎖定帳戶不會影響使用假定鎖定帳戶身份的代理用戶進行連接的能力。它也不會影響執行具有DEFINER屬性命名鎖定帳戶的存儲程序或視圖的能力。也就是說,鎖定帳戶不會影響使用代理帳戶或存儲的程序或視圖的能力。

帳戶鎖定功能取決於mysql.user系統表中account_locked列的存在。對於從5.7.6之前的MySQL版本進行的升級,請執行MySQL升級過程以確保該列存在。對於沒有account_locked列的未升級安裝,服務器會將所有帳戶視爲已解鎖,並且使用ACCOUNT LOCKACCOUNT UNLOCK子句會產生錯誤。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章