MySQL 存取權限系統(转帖)

MySQL中文參考手冊-權限(转自:http://sy3es.tnc.edu.tw/teaching/php_mysql/mysql.htm)

1 權限系統做什麼

MySQL權限系統的主要功能是証實連接到一台給定主機的一個用戶,並且賦予該用戶在一個資料庫上select、 insert、update和delete的權限。

附加的功能包括有一個匿名的用戶和對於MySQL特定的功能例如LOAD DATA INFILE進行授權及管理操作的能力。

2 MySQL 用戶名和密碼

由MySQL使用用戶名和密碼的方法與Unix或Windows使用的方式有很多不同之處:

    * MySQL使用於認証目的的用戶名,與Unix用戶名(登錄名字)或Windows用戶名無關。

    * MySQL用戶名最長可以是16各字符﹔典型地,Unix用戶名限制為8個字符。

    * MySQL密碼與Unix密碼沒關系。在你使用登錄到一台Unix機器密碼和你使用在那台機器上存取一個資料庫的密碼之間沒有必要有關聯。

    * MySQL加密密碼使用了一個Unix登錄期間所用的不同算法,使用PASSWORD()和ENCRYPT()函數部分。

3 使你的密碼安全

以一種暴露的可被其他用戶發現的方式指定你的密碼是不妥當的。當你運行客戶程式時,你可以使用下列方法指定你的密碼,還有每個方法的風險評估:

    * 使用一個在命令行上-pyour_pass或--password=your_pass的選項。這很方便但是不安全,因為你的密碼對系統狀態程式(例如ps)變得可見,它可以被其他的用戶調用來顯示命令行。(一般MySQL客戶在他們的初始化順序期間用零覆蓋命令行參數,但是仍然有一個短暫間隔時間內參數值可見的。)

    * 使用一個-p或--password選項(沒有指定your_pass值)。在這種情況下,客戶程式請求來自終端的密碼:

shell>mysql - u  user_name - p

Enter password: ********

      客戶回應“*”字符到作為輸入你的密碼的終端使得旁觀者不能看見它。因為它對其他用戶不可見,與在命令行上指定它相比,這樣進入你的密碼更安全。然而,這個輸入一個密碼的方法僅僅為你交互式運行程式是合適的。如果你想要從非交互式運行的一個腳本調用一個客戶,就沒有從終端輸入入密碼的機會。

4  MySQL提供的權限

權限資訊用user、db、host、tables_priv和columns_priv表被儲存在mysql資料庫中(即在名為mysql的資料庫中)。在MySQL啟動時和在6.9 權限修改何時生效所說的情況時,伺服器讀入這些資料庫表內容。

 

5 權限系統工作原理

MySQL權限系統保証所有的用戶可以嚴格地做他們假定被允許做的事情。當你連接一個MySQL伺服器時, 你的身份由你從那連接的主機和你指定的用戶名來決定,系統根據你的身份和你想做什麼來授予權限。

MySQL在認定身份中考慮你的主機名和用戶名字,是因為有很小的原因假定一個給定的用戶在網際網路上屬於同一個人。例如,用戶從whitehouse.gov連接的bill不必和從mosoft.com連接bill是同一個人。 MySQL通過允許你區分在不同的主機上碰巧有同樣名字用戶來處理它:你可以對從whitehouse.gov連接授與bill一個權限集,而為從microsoft.com的連接授予一個不同的權限集。

MySQL存取控制包含2個階段:

    * 階段1:伺服器檢查你是否允許連接。

    * 階段2:假定你能連接,伺服器檢查你發出的每個請求。看你是否有足夠的權限實施它。例如,如果你從資料庫中一個表選取(select)行或從資料庫拋棄一個表,伺服器確定你對表有select權限或對資料庫有drop權限。

 

6存取控制, 階段1:連接証實

當你試圖聯接一個MySQL伺服器時,伺服器基於你的身份和你是否能通過供應正確的密碼驗証身份來接受或拒絕連接。如果不是,伺服器完全具結你的存取,否則,伺服器接受連接,然後進入階段2並且等待請求。

你的身份基於2個資訊:

    * 你從那個主機連接

    * 你的MySQL用戶名

身份檢查使用3個user表(Host, User和Password)範圍字段執行。伺服器只有在一個user表條目匹配你的主機名和用戶名並且你提供了正確的密碼時才接受連接。

在user表範圍字段可以如下被指定:

    * 一個Host值可以是主機名或一個IP數字,或'localhost'指出本地主機。

    * 你可以在Host字段裡使用通配符字符“%”和“_”。

    * 一個Host值'%'匹配任何主機名,一個空白Host值等價於'%'。注意這些值匹配能創建一個連接到你的伺服器的任何主機!

    * 通配符字符在User字段中不允許,但是你能指定空白的值,它匹配任何名字。如果user表匹配到來的連接的條目有一個空白的用戶名,用戶被認為是匿名用戶(沒有名字的用戶),而非客戶實際指定的名字。這意味著一個空白的用戶名被用於在連接期間的進一步的存取檢查(即,在階段2期間)。

    * Password字段可以是空白的。這不意味著匹配任何密碼,它意味著用戶必須不指定一個密碼進行連接。



7 存取控制,階段2:請求証實

一旦你建立了一個連接,伺服器進入階段2。對在此連接上進來的每個請求,伺服器檢查你是否有足夠的權限來執行它,它基於你希望執行的操作類型。這正是在授權表中的權限字段發揮作用的地方。這些權限可以來子user、db、host、tables_priv或columns_priv表的任何一個。授權表用GRANT和REVOKE命令操作。見7.26 GRANT和REVOKE 句法。(你可以發覺參考6.6 權限系統怎樣工作很有幫助,它列出了在每個權限表中呈現的字段。)

user表在一個全局基礎上授予賦予你的權限,該權限不管當前的資料庫是什麼均適用。例如,如果user表授予你delete權限, 你可以刪除在伺服器主機上從任何資料庫刪除行!換句話說,user表權限是超級用戶權限。只把user表的權限授予超級用戶如伺服器或資料庫主管是明智的。對其他用戶,你應該把在user表中的權限設成'N'並且僅在一個特定資料庫的基礎上授權, 使用db和host表。

db和host表授予資料庫特定的權限。在範圍字段的值可以如下被指定:

    * 通配符字符“%”和“_”可被用於兩個表的Host和Db字段。

    * 在db表的'%'Host值意味著“任何主機”,在db表中一個空白Host值意味著“對進一步的資訊咨詢host表”。

    * 在host表的一個'%'或空白Host值意味著“任何主機”。

    * 在兩個表中的一個'%'或空白Db值意味著“任何資料庫”。

    * 在兩個表中的一個空白User值匹配匿名用戶。

db和host表在伺服器啟動時被讀取和排序(同時它讀user表)。db表在Host、Db和User範圍字段上排序,並且host表在Host和Db範圍字段上排序。對於user表,排序首先放置最特定的值然後最後最不特定的值,並且當伺服器尋找匹配入條目時,它使用它找到的第一個匹配。

tables_priv和columns_priv表授予表和列特定的權限。在範圍字段的值可以如下被指定:

    * 通配符“%”和“_”可用在使用在兩個表的Host字段。

    * 在兩個表中的一個'%'或空白Host意味著“任何主機”。

    * 在兩個表中的Db、Table_name和Column_name字段不能包含通配符或空白。

tables_priv和columns_priv表在Host、Db和User字段上被排序。這類似於db表的排序,盡管因為只有Host字段可以包含通配符,但排序更簡單。

 

8 權限更改何時生效

當mysqld啟動時,所有的授權表內容被讀進儲存器並且從那點生效。

用GRANT、REVOKE或SET PASSWORD對授權表施行的修改會立即被伺服器注意到。

如果你手工地修改授權表(使用INSERT、UPDATE等等),你應該執行一個FLUSH PRIVILEGES語句或運行mysqladmin flush-privileges告訴伺服器再裝載授權表,否則你的改變將不生效,除非你重啟伺服器。

當伺服器注意到授權表被改變了時,現存的客戶連接有如下影響:

    * 表和列權限在客戶的下一次請求時生效。

    * 資料庫權限改變在下一個USE db_name命令生效。

全局權限的改變和密碼改變在下一次客戶連接時生效。

9 建立初始的MySQL權限

你的安裝初始時廣開大門,你首先應該做的事情之一是為MySQL root用戶指定一個密碼。你可以做如下(注意,你使用PASSWORD()函數指定密碼):

shell> mysql -u root mysql

mysql> UPDATE user SET Password=PASSWORD('new_password')

           WHERE user='root';

mysql> FLUSH PRIVILEGES;

在MySQL 3.22和以上版本中,你可以使用SET PASSWORD語句:

shell> mysql -u root mysql

mysql> SET PASSWORD FOR root=PASSWORD('new_password');

設置密碼的另一種方法是使用mysqladmin命令:

shell> mysqladmin -u root password new_password

注意:如果你使用第一種方法在user表裡直接更新密碼,你必須告訴伺服器再次讀入授權表(用FLUSH PRIVILEGES),因為否則改變將不被注意到。

一旦root密碼被設置,此後當你作為root與伺服器連接時,你必須供應那個密碼。

 

10 向MySQL增加新用戶權限

你可以有2個不同的方法增加用戶:通過使用GRANT語句或通過直接操作MySQL授權表。比較好的方法是使用GRANT語句,因為他們是更簡明並且好像錯誤少些。

下面的例子顯示出如何使用mysql客戶安裝新用戶。這些例子假定權限根據以前的章節描述的內定被安裝。這意味著為了改變,你必須在mysqld正在運行同一台機器上,你必須作為MySQL root用戶連接,並且root用戶必須對mysql資料庫有insert權限和reload管理權限。另外,如果你改變了root用戶密碼,你必須如下的mysql命令指定它。

你可以通過發出GRANT語句增加新用戶:

shell> mysql --user=root mysql

mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost

           IDENTIFIED BY 'something' WITH GRANT OPTION;

mysql> GRANT ALL PRIVILEGES ON *.* TO monty@"%"

           IDENTIFIED BY 'something' WITH GRANT OPTION;

mysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;

mysql> GRANT USAGE ON *.* TO dummy@localhost;

這些GRANT語句安裝3個新用戶:

monty

    可以從任何地方連接伺服器的一個完全的超級用戶,但是必須使用一個密碼('something'做這個。注意,我們必須對monty@localhost和monty@"%"發出GRANT語句。如果我們增加localhost條目,對localhost的匿名用戶條目在我們從本地主機連接接時由mysql_install_db創建的條目將優先考慮,因為它有更特定的Host字段值,所以以user表排列順序看更早到來。

admin

    可以從localhost沒有一個密碼進行連接並且被授予reload和process管理權限的用戶。這允許用戶執行mysqladmin reload、mysqladmin refresh和mysqladmin flush-*命令,還有mysqladmin processlist。沒有授予資料庫有關的權限。他們能在以後通過發出另一個GRANT語句授權。

dummy

    可以不用一個密碼連接的一個用戶,但是只能從本地主機。全局權限被設置為'N'--USAGE權限類型允許你無需權限就可設置一個用戶。它假定你將在以後授予資料庫相關的權限。

你也可以直接通過發出INSERT語句增加同樣的用戶存取資訊,然後告訴伺服器再次裝入授權表:

shell> mysql --user=root mysql

mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD('something'),

                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')

mysql> INSERT INTO user VALUES('%','monty',PASSWORD('something'),

                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')

mysql> INSERT INTO user SET Host='localhost',User='admin',

                 Reload_priv='Y', Process_priv='Y';

mysql> INSERT INTO user (Host,User,Password)

                        VALUES('localhost','dummy','');

mysql> FLUSH PRIVILEGES;

取決於你的MySQL版本,對上述,你可能必須使用一個不同數目'Y'值(在3.22.11以前的版本有更少的權限列)。對admin用戶,只用在3.22.11開始的版本具有的更加可讀的INSERT擴充的語法。

注意,為了設置一個超級用戶,你只需創造一個user表條目,其權限字段設為'Y'。不需要db或host表的條目。

在user表中的權限列不是由最後一個INSERT語句明確設置的(對dummy用戶),因此那些列被賦予內定值'N'。這是GRANT USAGE做的同樣的事情。

下列例子增加一個用戶custom,他能從主機localhost、server.domain和whitehouse.gov連接。他只想要從localhost存取bankaccount資料庫,從whitehouse.gov存取expenses資料庫和從所有3台主機存取customer資料庫。他想要從所有3台主機上使用密碼stupid。

為了使用GRANT語句設置個用戶的權限,運行這些命令:

shell> mysql --user=root mysql

mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP

           ON bankaccount.*

           TO custom@localhost

           IDENTIFIED BY 'stupid';

mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP

           ON expenses.*

           TO custom@whitehouse.gov

           IDENTIFIED BY 'stupid';

mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP

           ON customer.*

           TO custom@'%'

           IDENTIFIED BY 'stupid';

通過直接修改授權表設置用戶權限,運行這些命令(注意,在結束時FLUSH PRIVILEGES):

shell> mysql --user=root mysql

mysql> INSERT INTO user (Host,User,Password)

       VALUES('localhost','custom',PASSWORD('stupid'));

mysql> INSERT INTO user (Host,User,Password)

       VALUES('server.domain','custom',PASSWORD('stupid'));

mysql> INSERT INTO user (Host,User,Password)

       VALUES('whitehouse.gov','custom',PASSWORD('stupid'));

mysql> INSERT INTO db

       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,

        Create_priv,Drop_priv)

       VALUES

       ('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');

mysql> INSERT INTO db

       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,

        Create_priv,Drop_priv)

       VALUES

       ('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y');

mysql> INSERT INTO db

       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,

        Create_priv,Drop_priv)

       VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y');

mysql> FLUSH PRIVILEGES;

頭3個INSERT語句增加user表條目,允許用戶custom用給定密碼從不同的主機進行連接,但是沒有授予任何許可(所有權限被設置為內定值'N')。後3個INSERT語句增加db表條目,授予custom以bankaccount、expenses和customer資料庫權限,但是只能在從正確的主機存取時。通常,在授權表直接被修改時,伺服器必須被告知再次裝入他們(用FLUSH PRIVILEGES)以便使權限修改生效。

如果你想要給特定的用戶從一個給定的域上的任何機器上存取權限,你可以發出一個如下的GRANT語句:

mysql> GRANT ...

           ON *.*

           TO myusername@"%.mydomainname.com"

           IDENTIFIED BY 'mypassword';

為了通過直接修改授權表做同樣的事情,這樣做:

mysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername',

           PASSWORD('mypassword'),...);

mysql> FLUSH PRIVILEGES;

 

11 怎樣設置密碼

在前面小節的例子裡說明了一個重要的原則:當你使用INSERT或UPDATE語句儲存一個非空的密碼時,你必須使用PASSWORD()函數加密它。這是因為在user表刈脛加密形式儲存密碼,而不是作為純文本。如果你忘記這個事實,你可能像這樣試圖設置密碼:

shell> mysql -u root mysql

mysql> INSERT INTO user (Host,User,Password) VALUES('%','jeffrey','biscuit');

mysql> FLUSH PRIVILEGES

結果是純文本值'biscuit'作為密碼被儲存在user表中。在用戶jeffrey試圖用這個密碼連接伺服器時,mysql客戶用PASSWORD()加密它並且將結果送給伺服器,伺服器比較在user表中的值(它是純文本值'biscuit')和加密的密碼(而不是 'biscuit'),比較失敗並且伺服器拒絕連接:

shell> mysql -u jeffrey -pbiscuit test

Access denied

因為當他們被插入user表時,密碼必須被加密,相反,INSERT語句應該像這樣被指定:

mysql> INSERT INTO user (Host,User,Password)

       VALUES('%','jeffrey',PASSWORD('biscuit'));

當你使用SET PASSWORD語句時,你也必須使用PASSWORD()函數:

mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('biscuit');

如果你使用GRANT ... IDENTIFIED BY語句或mysqladmin password命令設置密碼,PASSWORD()函數是不必要的。他們都考慮到為你加密密碼,多以你可像這樣指定一個密碼'biscuit':

mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'biscuit';

shell> mysqladmin -u jeffrey password biscuit

注意: PASSWORD()不是以在Unix密碼加密的同樣方法施行密碼加密。你不應該假定如果你的Unix密碼和你的MySQL密碼是一樣的,PASSWORD()將導致與在Unix密碼文件被儲存的同樣的加密值。