直播中
作 者: 晏子
2.1.3 數(shù)據(jù)庫和表權(quán)限
下列權(quán)限運用于數(shù)據(jù)庫和表上的操作。
ALTER
允許你使用ALTER TABLE語句,這其實是一個簡單的第一級權(quán)限,你必須由其他權(quán)限,這看你想對數(shù)據(jù)庫實施什么操作。
CREATE
允許你創(chuàng)建數(shù)據(jù)庫和表,但不允許創(chuàng)建索引。
DELETE
允許你從表中刪除現(xiàn)有記錄。
DROP
允許你刪除(拋棄)數(shù)據(jù)庫和表,但不允許刪除索引。
INDEX
允許你創(chuàng)建并刪除索引。
REFERENCES
目前不用。
SELECT
允許你使用SELECT語句從表中檢索數(shù)據(jù)。對不涉及表的SELECT語句就不必要,如SELECT NOW()或SELECT 4/2。
UPDATE
允許你修改表中的已有的記錄。
2.1.4 管理權(quán)限
下列權(quán)限運用于控制服務(wù)器或用戶授權(quán)能力的操作的管理性操作。
FILE
允許你告訴服務(wù)器讀或?qū)懛?wù)器主機上的文件。該權(quán)限不應(yīng)該隨便授予,它很危險,見“回避授權(quán)表風險”。服務(wù)器確實較謹慎地保持在一定范圍內(nèi)使用該權(quán)限。你只能讀任何人都能讀的文件。你正在寫的文件必須不是現(xiàn)存的文件,這防止你迫使服務(wù)器重寫重要文件,如/etc/passwd或?qū)儆趧e人的數(shù)據(jù)庫的數(shù)據(jù)目錄。
如果你授權(quán)FILE權(quán)限,確保你不以UNIX的root用戶運行服務(wù)器,因為root可在文件系統(tǒng)的任何地方創(chuàng)建新文件。如果你以一個非特權(quán)用戶運行服務(wù)器,服務(wù)器只能在給用戶能訪問的目錄中創(chuàng)建文件。
GRANT
允許你將你自己的權(quán)限授予別人,包括GRANT。
PROCESS
允許你通過使用SHOW PROCESS語句或mysqladmin process命令查看服務(wù)器內(nèi)正在運行的線程(進程)的信息。這個權(quán)限也允許你用KILL語句或mysqladmin kill命令殺死線程。
你總是能看到或殺死你自己的線程。PROCESS權(quán)限賦予你對任何線程做這些事情的能力。
RELOAD
允許你執(zhí)行大量的服務(wù)器管理操作。你可以發(fā)出FLUSH語句,你也能指性mysqladmin的reload、refresh、flush-hosts、flush-logs、flush-privileges和flush-tables等命令。
SHUTDOWN
允許你用mysqladmin shutdown關(guān)閉服務(wù)器。
在user、db和host表中,每一個權(quán)限以一個單獨的列指定。這些列全部聲明為一個ENUM("N","Y")類型,所以每個權(quán)的缺省值是“N”。在tables_priv和columns_priv中的權(quán)限以一個SET表示,它允許權(quán)限用一個單個列以任何組合指定。這兩個表比其他三個表更新,這就是為什么它們使用更有效的表示方式的原因。(有可能在未來,user、db和host表也用一個SET類型表示。)
在tables_priv表中的Table_priv列被定義成:
SET('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter')
在coloums_priv表中的Column_priv列被定義成:
SET('Select','Insert','Update','References')
列權(quán)限比表權(quán)限少,因為列級較少的權(quán)限有意義。例如你能創(chuàng)建一個表,但你不能創(chuàng)建一個孤立的列。
user表包含某些在其他授權(quán)表不存在的權(quán)限的列:File_priv、Process_priv、Reload_priv和Shutdown_priv。這些權(quán)限運用于你讓服務(wù)器執(zhí)行的與任何特定數(shù)據(jù)庫或表不相關(guān)的操作。如允許一個用戶根據(jù)當前數(shù)據(jù)庫是什么來關(guān)閉數(shù)據(jù)庫是毫無意義的。
2.2 服務(wù)器如何控制客戶訪問
在你使用MySQL時,客戶訪問控制有兩個階段。第一階段發(fā)生在你試圖連接服務(wù)器時。服務(wù)器查找user表看它是否能找到一個條目匹配你的名字、你正在從那兒連接的主機和你提供的口令。如果沒有匹配,你就不能連接。如果有一個匹配,建立連接并繼續(xù)第二階段。在這個階段,對于每一個你發(fā)出的查詢,服務(wù)器檢查授權(quán)表看你是否有足夠的權(quán)限執(zhí)行查詢,第二階段持續(xù)到你與服務(wù)器對話的結(jié)束。
本小節(jié)詳細介紹MySQL服務(wù)器用于將授權(quán)表條目匹配到來的連接請求或查詢的原則,這包括在授權(quán)表范圍列中合法的值的類型、結(jié)合授權(quán)表中的權(quán)限信息的方式和表中條目被檢查的次序。
2.2.1 范圍列內(nèi)容
一些范圍列要求文字值,但它們大多數(shù)允許通配符或其他特殊值。
Host
一個Host列值可以是一個主機名或一個IP地址。值localhost意味著本地主機,但它只在你用一個localhost主機名時才匹配,而不是你在使用主機名時。假如你的本地主機名是pit.snake.net并且在user表中有對你的兩條記錄,一個有一個Host值或localhost,而另一個有pit.snake.net,有l(wèi)ocalhost的記錄將只當你連接localhost時匹配,其他在只在連接pit.snake.net時才匹配。如果你想讓客戶能以兩種方式連接,你需要在user表中有兩條記錄。
你也可以用通配符指定Host值??梢允褂肧QL的模式字符“%”和“_”并具有當你在一個查詢中使用LIKE算符同樣的含義(不允許regex算符)。 SQL模式字符都能用于主機名和IP地址。如%wisc.edu匹配任何wisc.edu域內(nèi)的主機,而%.edu匹配任何教育學(xué)院的主機。類似地,192.168.%匹配任何在192.168 B類子網(wǎng)的主機,而192.168.3.%匹配任何在192.168.3 C類子網(wǎng)的主機。
%值匹配所有主機,并可用于允許一個用戶從任何地方連接。一個空白的Host值等同于%。(例外:在db表中,一個空白Host值含義是“進一步檢查host表”,該過程在“查詢訪問驗證”中介紹。)
從MySQL 3.23起,你也可以指定帶一個表明那些為用于網(wǎng)絡(luò)地址的網(wǎng)絡(luò)掩碼的IP地址,如192.168.128.0/17指定一個17位網(wǎng)絡(luò)地址并匹配其IP地址是192.168128前17位的任何主機。
User
用戶名必須是文字的或空白。一個空白值匹配任何用戶。%作為一個User值不意味著空白,相反它匹配一個字面上的%名字,這可能不是你想要的。
當一個到來的連接通過user表被驗證而匹配的記錄包含一個空白的User值,客戶被認為是一個匿名用戶。
Password
口令值可以是空或非空,不允許用通配符。一個空口令不意味著匹配任何口令,它意味著用戶必須不指定口令。
口令以一個加密過的值存儲,不是一個字面上的文本。如果你在Password列中存儲一個照字面上的口令,用戶將不能連接!GRANT語句和mysqladmin password命令為你自動加密口令,但是如果你用諸如INSERT、REPLACE、UPDATE或SET PASSWORD等命令,一定要用PASSWORD("new_password")而不是簡單的"new_password"來指定口令。
Db
在columns_priv和tables_priv表中,Db值必須是真正的數(shù)據(jù)庫名(照字面上),不允許模式和空白。在db和host中,Db值可以以字面意義指定或使用SQL模式字符'%'或'_'指定一個通配符。一個'%'或空白匹配任何數(shù)據(jù)庫。
Table_name,Column_name
這些列中的值必須是照字面意思的表或列名,不允許模式和空白。
某些范圍列被服務(wù)器視為大小寫敏感的,其余不是。這些原則總結(jié)在下表中。特別注意Table_name值總是被看作大小寫敏感的,即使在查詢中的表名的大小寫敏感性對待視服務(wù)器運行的主機的文件系統(tǒng)而定(UNIX下是大小寫敏感,而Windows不是)。
表3 授權(quán)表范圍列的大小寫敏感性
列
Host
User
Password
Db
Table_name
Column_name
大小寫敏感性
No
Yes
Yes
Yes
Yes
No
2.2.2 查詢訪問驗證
每次你發(fā)出一個查詢,服務(wù)器檢查你是否有足夠的權(quán)限執(zhí)行它,它以user、db、tables_priv和columns_priv的順序檢查,知道它確定你有適當?shù)脑L問權(quán)限或已搜索所有表而一無所獲。更具體的說:
服務(wù)器檢查user表匹配你開始連接的記錄以查看你有什么全局權(quán)限。如果你有并且它們對查詢足夠了,服務(wù)器則執(zhí)行它。
如果你的全局權(quán)限不夠,服務(wù)器為你在db表中尋找并將該記錄中的權(quán)限加到你的全局權(quán)限中。如果結(jié)果對查詢足夠,服務(wù)器執(zhí)行它。
如果你的全局和數(shù)據(jù)庫級組合的權(quán)限不夠,服務(wù)器繼續(xù)查找,首先在tables_priv表,然后columns_priv表。
如果你在檢查了所有表之后仍無權(quán)限,服務(wù)器拒絕你執(zhí)行查詢的企圖。
用布爾運算的術(shù)語,授權(quán)表中的權(quán)限被服務(wù)器這樣使用:
user OR tables_priv OR columns_priv
你可能疑惑為什么前面的描述只引用4個授權(quán)表,而實際上有5個。實際上服務(wù)器是這樣檢查訪問權(quán)限:
user OR (db AND host) OR tables_priv OR columns_priv
第一個較簡單的表達式是因為host表不受GRANT和REVOKE語句影響。如果你總是用GRANT和REVOKE管理用戶權(quán)限,你絕不需要考慮host表。但是其工作原理你用該知道:
當服務(wù)器檢查數(shù)據(jù)庫級權(quán)限時,它對于客戶查找db表。如果Host列是空的,它意味著“檢查host表以找出哪一個主機能訪問數(shù)據(jù)庫”。
服務(wù)器在host表中查找有與來自db表的記錄相同的Db列值。如果沒有host記錄匹配客戶主機,則沒有授予數(shù)據(jù)庫級權(quán)限。如果這些記錄的任何一個的確有一個匹配連接的客戶主機的Host列值,db表記錄和host表記錄結(jié)合產(chǎn)生客戶的數(shù)據(jù)庫級權(quán)限。
然而,權(quán)限用一個邏輯AND(與)結(jié)合起來,這意味著除非一個給定的權(quán)限在兩個表中都有,否則客戶就不具備該權(quán)限。以這種方式,你可以在db表中授予一個基本的權(quán)限集,然后使用host表對特定的主機有選擇地禁用它們。如你可以允許從你的域中的所有主機訪問數(shù)據(jù)庫,但關(guān)閉了那些在較不安全區(qū)域的主機的數(shù)據(jù)庫權(quán)限。
前面的描述毫無疑問使訪問檢查聽起來一個相當復(fù)雜的過程,特別是你以為服務(wù)器對你發(fā)出的每個查詢進行權(quán)限檢查,然而此過程是很快的,因為服務(wù)器其實不從授權(quán)表對每個查詢查找信息,相反,它在啟動時將表的內(nèi)容讀入內(nèi)存,然后驗證查詢用的是內(nèi)存中的副本。這大大提高了訪問檢查操作的性能。但有一個非常明顯的副作用。如果你直接修改授權(quán)表的內(nèi)容,服務(wù)器將不知道權(quán)限的改變。
例如,如果你用一條INSERT語句向user表加入一個新記錄來增加一個新用戶,命名在記錄中的用戶將不能連接服務(wù)器。這對管理員新手(有時對有經(jīng)驗的老手)是很困惑的事情,當時解決方法很簡單:在你改變了它們之后告訴服務(wù)器重載授權(quán)表內(nèi)容,你可以發(fā)一條FLUSH PRIVILEGES或執(zhí)行mysqladmin flush-privileges(或如果你有一個不支持flush-privileges的老版本,用mysqladmin reload。)。
2.2.3 范圍列匹配順序
MySQL服務(wù)器按一種特定方式排序符授權(quán)表中的記錄,然后通過按序瀏覽記錄匹配到來的連接。找到的第一個匹配決定了被使用的記錄。理解MySQL使用的排序順序很重要,特別是對user表。
當服務(wù)器讀取user表內(nèi)容時,它根據(jù)在Host和User列中的值排序記錄,Host值起決定作用(相同的Host值排在一起,然后再根據(jù)User值排序)。然而,排序不是典序(按詞排序),它只是部分是。要牢記的是字面上的詞優(yōu)先于模式。這意味著如果你正從client.your.net連接服務(wù)器而Host有client.your.net和%.your.net兩個值,則第一個先選。類似地,%.your.net優(yōu)先于%.net,然后是%。IP地址的匹配也是這樣的。
總之一句話,越具體越優(yōu)先。可以參見本文附錄的實例。
2.3 避免授權(quán)表風險
本屆介紹一些在你授權(quán)時的一些預(yù)防措施,以及不明值的選擇帶來的風險。一般地,你要很“吝嗇”地授予超級用戶權(quán)限,即不要啟用user表中條目中的權(quán)限,而使用其它授權(quán)表,以將用戶權(quán)限限制于數(shù)據(jù)庫、表、或列。在user表中的權(quán)限允許于影響到你的服務(wù)器操作或能訪問任何數(shù)據(jù)庫中的任何表。
不要授予對mysql數(shù)據(jù)庫的權(quán)限。一個擁有包含授權(quán)表數(shù)據(jù)庫權(quán)限的用戶可能會修改表以獲取對其他任何數(shù)據(jù)庫的權(quán)限。授予允許一個用戶修改mysql數(shù)據(jù)庫表的權(quán)限也實際上給了用戶以一個全局GRANT權(quán)限。如果用戶能直接修改表,這也等價于能夠發(fā)出任何你能想象的任何GRANT語句。
FILE權(quán)限尤其危險,不要輕易授權(quán)它。以下是一個擁有FILE權(quán)限的人能干除的事情:
CREATE TABLE etc_passwd (pwd_entry TEXT);
LOAD DATA INFILE "/etc/passwd" into TABLE etc_passwd;
SELECT * FROM etc_passwd;
在發(fā)出這些語句后,用戶已經(jīng)擁有了你的口令文件的內(nèi)容了。實際上,服務(wù)器上任何公開可讀文件的內(nèi)容都可被擁有FILE權(quán)限的用戶通過網(wǎng)絡(luò)訪問。
FILE權(quán)限也能被利用來危害沒有設(shè)置足夠權(quán)限制的文件權(quán)限的系統(tǒng)上的數(shù)據(jù)庫。這就是你為什么應(yīng)該設(shè)置數(shù)據(jù)目錄只能由服務(wù)器讀取的原因。如果對應(yīng)于數(shù)據(jù)庫表的文件可被任何人讀取,不只是用戶服務(wù)器賬號的用戶可讀,任何有FILE權(quán)限的用戶也可通過網(wǎng)絡(luò)連接并讀取它們。下面演示這個過程:
創(chuàng)建一個有一個LONGBLOB列的表:
USER test;
CREATE TABLE tmp (b LONGBLOB);
使用該表讀取每個對應(yīng)于你想偷取的數(shù)據(jù)庫表文件的內(nèi)容,然后將表內(nèi)容寫入你自己數(shù)據(jù)庫的一個文件中:
LOAD DATA INFILE "./other_db/x.frm" INTO TABLE tmp
FIELDS ESCAPED BY "" LINES TERMINATED BY "";
SELECT * FROM tmp INTO OUTFILE "y.frm"
FIELDS ESCAPED BY "" LINES TERMINATED BY "";
DELETE FROM tmp;
LOAD DATA INFILE "./other_db/x.ISD" INTO TABLE tmp
FIELDS ESCAPED BY "" LINES TERMINATED BY "";
SELECT * FROM tmp INTO OUTFILE "y.ISD"
FIELDS ESCAPED BY "" LINES TERMINATED BY "";
DELETE FROM tmp;
LOAD DATA INFILE "./other_db/x.ISM" INTO TABLE tmp
FIELDS ESCAPED BY "" LINES TERMINATED BY "";
SELECT * FROM tmp INTO OUTFILE "y.ISM"
現(xiàn)在你擁有了一個新表y,它包含other_db.x的內(nèi)容并且你有全權(quán)訪問它。
為避免讓人以同樣的方式攻擊,根據(jù)“第一部分 內(nèi)部安全性-保護你的數(shù)據(jù)目錄”中的指令設(shè)置你的數(shù)據(jù)目錄上的權(quán)限。你也可以在你啟動服務(wù)器時使用--skip-show-database選項限制用戶對于他們沒用訪問權(quán)限的數(shù)據(jù)庫使用SHOW DATABASES和SHOW TABLES。這有助于防止用戶找到關(guān)于它們不能訪問的數(shù)據(jù)庫和表的信息。
ALTER權(quán)限能以不希望的方式使用。假定你想讓user1可以訪問table1但不能訪問tables2。一個擁有ALTER權(quán)限的用戶可以通過使用ALTER TABLE將table2改名為table1來偷梁換柱。
當心GRANT權(quán)限。兩個由不同權(quán)限但都有GRANT權(quán)限的用戶可以使彼此的權(quán)利更強大。