MySQL安全性指南(2)
2.1.3 資料庫和表格權限
下列權限運送用於資料庫和表格上的操作。
ALTER
允許你使用ALTER
TABLE語句,這其實是一個簡單的第一級權限,你必須由其他權限,這看你想對資料庫實作什麼操作。
CREATE
允許你建立資料庫和表,但不允許建立索引。
DELETE
允許你從表格中刪除現有記錄。
DROP
允許你刪除(拋棄)資料庫和表,但不允許刪除索引。
INDEX
允許你建立並刪除索引。
REFERENCES
目前不用。
SELECT
允許你使用SELECT語句從表格中檢索資料。不涉及表格的SELECT語句就不必要,如SELECT NOW()或SELECT 4/2。
UPDATE
允許你修改表格中的已有的記錄。
2.1.4
管理權限
下列權限運用於控制伺服器或使用者授權能力的操作的管理性操作。
FILE
允許你告訴伺服器讀或寫伺服器主機上的檔案。該權限不應該隨便授予,它很危險,請參閱「迴避授權表風險」。伺服器確實較謹慎地保持在一定範圍內使用該權限。你只能讀任何人都能讀的文件。你正在寫的文件必須不是現存的文件,這防止你迫使伺服器重寫重要文件,如/etc/passwd或屬於別人的資料庫的資料目錄。
如果你授權FILE權限,確保你不以UNIX的root使用者執行伺服器,因為root可在檔案系統的任何地方建立新檔案。如果你以一個非特權使用者執行伺服器,伺服器只能在給使用者能存取的目錄中建立檔案。
GRANT
允許你將自己的權限授予別人,包括GRANT。
PROCESS
允許你透過使用SHOW
PROCESS語句或mysqladmin process指令查看伺服器內正在執行的執行緒(進程)的資訊。這個權限也允許你用KILL語句或mysqladmin
kill命令殺死線程。
你總是能看到或殺死你自己的線程。 PROCESS權限賦予你對任何執行緒做這些事情的能力。
RELOAD
允許你執行大量的伺服器管理操作。你可以發出FLUSH語句,你也能指性mysqladmin的reload、refresh、flush-hosts、flush-logs、flush-privileges和flush-tables等指令。
SHUTDOWN
允許你用mysqladmin shutdown關閉伺服器。
在user、db和host表中,每一個權限以一個單獨的欄位指定。這些欄位全部宣告為一個ENUM("N","Y")類型,所以每個權的預設值是「N」。在tables_priv和columns_priv中的權限以一個SET表示,它允許權限以單一列以任何組合指定。這兩個表比其他三個表更新,這就是為什麼它們使用更有效的表示方式的原因。 (有可能在未來,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')
列權限比表權限少,因為列級較少的權限有意義。例如你能建立一個表,但你不能建立一個孤立的列。
user表包含某些在其他授權表不存在的權限的欄位:File_priv、Process_priv、Reload_priv和Shutdown_priv。這些權限運用於你讓伺服器執行的與任何特定資料庫或表格不相關的操作。如允許一個使用者根據當前資料庫是什麼來關閉資料庫是毫無意義的。
2.2
伺服器如何控制客戶存取
在你使用MySQL時,客戶存取控制有兩個階段。第一階段發生在你試圖連接伺服器時。伺服器尋找user表看它是否能找到一個條目來匹配你的名字、你正在從那裡連接的主機和你提供的口令。如果沒有匹配,你就不能連接。如果有一個匹配,建立連接並繼續第二階段。在這個階段,對於每一個你發出的查詢,伺服器檢查授權表看你是否有足夠的權限執行查詢,第二階段持續到你與伺服器對話的結束。
本小節詳細介紹MySQL伺服器用於將授權表條目匹配到來的連接請求或查詢的原則,這包括在授權表範圍列中合法的值的類型、結合授權表中的權限資訊的方式和表中條目被檢查的次序。
2.2.1
範圍列內容
一些範圍列要求文字值,但它們大多數允許通配符或其他特殊值。
Host
一個Host列值可以是一個主機名稱或一個ip位址。值localhost意味著本機,但它只在你用一個localhost主機名稱時才匹配,而不是你在使用主機名稱時。假如你的本地主機名稱是pit.snake.net並且在user表中有對你的兩條記錄,一個有一個Host值或localhost,而另一個有pit.snake.net,有localhost的記錄將只當你連接localhost時匹配,其他在只連接pit.snake.net時才匹配。如果你想讓客戶能以兩種方式連接,你需要在user表中有兩筆記錄。
你也可以用通配符指定Host值。可以使用SQL的模式字元「%」和「_」並且具有當你在一個查詢中使用LIKE算符同樣的含義(不允許regex算符)。
SQL模式字元都能用於主機名稱和IP位址。如%wisc.edu符合任何wisc.edu網域內的主機,而%.edu則符合任何教育學院的主機。類似地,192.168.%匹配任何在192.168
B類子網路的主機,而192.168.3.%符合任何在192.168.3
C類子網路的主機。
%值符合所有主機,並可用於允許一個使用者從任何地方連接。一個空白的Host值等同於%。 (例外:在db表中,一個空白Host值含義是“進一步檢查host表”,該過程在“查詢訪問驗證”中介紹。)
從MySQL
3.23起,你也可以指定帶一個表明那些為用於網路位址的網路遮罩的IP位址,如192.168.128.0/17指定一個17位元網路位址並匹配其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值必須是真正的資料庫名稱(照字面上),不允許模式和空白。在db和host中,Db值可以以字面意義指定或使用SQL模式字元'%'或'_'指定一個通配符。一個'%'或空白匹配任何資料庫。
Table_name,Column_name
這些欄位中的值必須是照字面意思的表或列名,不允許模式和空白。
某些範圍列被伺服器視為大小寫敏感的,其餘則不是。這些原則總結在下表中。特別注意Table_name值總是被視為大小寫敏感的,即使在查詢中的表名的大小寫敏感性對待視伺服器運行的主機的檔案系統而定(UNIX下是大小寫敏感,而Windows不是)。
表3
授權表範圍列的大小寫敏感性
欄
Host
User
Password
Db
Table_name
Column_name
大小寫敏感性
No
Yes
Yes
Yes
Yes🜎
查詢存取驗證
每次你發出一個查詢,伺服器檢查你是否有足夠的權限執行它,它以user、db、tables_priv和columns_priv的順序檢查,知道它確定你有適當的訪問權限或已搜索所有表而一無所獲。更具體的說:
伺服器檢查user表匹配你開始連接的記錄以查看你有什麼全域權限。如果你有並且它們對查詢足夠了,伺服器則執行它。
如果你的全域權限不夠,伺服器為你在db表中尋找並將該記錄中的權限加到你的全域權限中。如果結果對查詢足夠,伺服器執行它。
如果你的全域和資料庫層級組合的權限不夠,伺服器繼續查找,首先在tables_priv表,然後columns_priv表。
如果你在檢查了所有表之後仍無權限,伺服器拒絕你執行查詢的企圖。
用布林運算的術語,授權表中的權限被伺服器這樣使用:
user OR
tables_priv OR
columns_priv
你可能疑惑為什麼前面的描述只引用4個授權表,而實際上有5個。實際上伺服器是這樣檢查存取權限:
user
OR (db AND host) OR tables_priv OR
columns_priv
第一個較簡單的表達式是因為host表不受GRANT和REVOKE語句影響。如果你總是用GRANT和REVOKE管理使用者權限,絕對不需要考慮host表。但其工作原理你用該知道:
當伺服器檢查資料庫級權限時,它對於客戶查找db表。如果Host欄位是空的,它表示「檢查host表以找出哪一個主機能存取資料庫」。
伺服器在host表中尋找有與來自db表的記錄相同的Db列值。如果沒有host記錄匹配客戶主機,則沒有授予資料庫級權限。如果這些記錄的任何一個的確有一個匹配連接的客戶主機的Host列值,db表記錄和host表記錄結合產生客戶的資料庫級權限。
然而,權限用一個邏輯AND(與)結合起來,這意味著除非一個給定的權限在兩個表中都有,否則客戶就不具備該權限。以這種方式,你可以在db表中授予一個基本的權限集,然後使用host表對特定的主機選擇性地停用它們。如你可以允許從你的網域中的所有主機存取資料庫,但關閉了那些在較不安全區域的主機的資料庫權限。
前面的描述毫無疑問地讓存取檢查聽起來一個相當複雜的過程,特別是你以為伺服器對你發出的每個查詢進行權限檢查,然而此過程是很快的,因為伺服器其實不從授權表對每個查詢查找信息,相反,它在啟動時將表的內容讀入內存,然後驗證查詢用的是內存中的副本。這大大提高了存取檢查操作的效能。但有一個非常明顯的副作用。如果你直接修改授權表的內容,伺服器將不知道權限的改變。
例如,如果你用一條INSERT語句向user表加入一個新記錄來增加一個新用戶,命名在記錄中的用戶將不能連接伺服器。這對管理員新手(有時對有經驗的老手)是很困惑的事情,當時解決方法很簡單:在你改變了它們之後告訴伺服器重載授權表內容,你可以發一條FLUSH
PRIVILEGES或執行mysqladmin
flush-privileges(或者如果你有一個不支援flush-privileges的老版本,用mysqladmin
reload。 )。
2.2.3
範圍列符合順序
MySQL伺服器以特定方式排序符授權表中的記錄,然後透過依序瀏覽記錄來匹配到來的連線。找到的第一個匹配決定了被使用的記錄。理解MySQL使用的排序順序很重要,特別是對user表。
當伺服器讀取user表內容時,它根據在Host和User列中的值排序記錄,Host值起決定作用(相同的Host值排在一起,然後再根據User值排序)。然而,排序不是典序(按詞排序),它只是部分是。要牢記的是字面上的字詞優先於模式。這表示如果你正從client.your.net連接伺服器而Host有client.your.net和%.your.net兩個值,則第一個先選。類似地,%.your.net優先於%.net,然後是%。 IP位址的匹配也是這樣的。
總會之一句話,越具體越優先。可以參見本文附錄的實例。
2.3
避免授權表風險
本屆介紹一些在你授權時的一些預防措施,以及不明值的選擇所帶來的風險。一般地,你要很「吝嗇」地授予超級使用者權限,也就是不要啟用user表中條目中的權限,而使用其它授權表,以將使用者權限限制於資料庫、表、或列。在user表中的權限允許於影響到你的伺服器操作或能存取任何資料庫中的任何表。
不要授予對mysql資料庫的權限。一個擁有包含授權表資料庫權限的使用者可能會修改表格以取得對其他任何資料庫的權限。授予允許一個使用者修改mysql資料庫表的權限也實際上給了使用者以一個全域GRANT權限。如果使用者能直接修改表,這也等價於能夠發出任何你能想像的任何GRANT語句。
FILE權限尤其危險,不要輕易授權它。以下是擁有FILE權限的人能幹除的事:
CREATE
TABLE etc_passwd (pwd_entry TEXT);
LOAD DATA INFILE "/etc/passwd" into
TABLE etc_passwd;
SELECT * FROM
etc_passwd;
在發出這些語句後,使用者已經擁有了你的口令檔案的內容了。實際上,伺服器上任何公開可讀檔案的內容都可被擁有FILE權限的使用者透過網路存取。
FILE權限也能被利用來危害沒有設定足夠權限的檔案權限的系統上的資料庫。這就是為什麼你應該設定資料目錄只能由伺服器讀取的原因。如果對應於資料庫表格的檔案可被任何人讀取,不只是使用者伺服器帳號的使用者可讀,任何有FILE權限的使用者也可透過網路連線並讀取它們。下面示範這個過程:
建立一個有一個LONGBLOB欄位的表格:
USER test;
CREATE TABLE tmp (b
LONGBLOB);
使用該表讀取每個對應於你想偷取的資料庫表格檔案的內容,然後將表格內容寫入你自己資料庫的一個檔案:
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"
現在你擁有了一個新表y,它包含other_db.x的內容並且你有全權訪問它。
為避免讓人以同樣的方式攻擊,根據「第一部分
內部安全性-保護你的資料目錄」中的指令設定你的資料目錄上的權限。你也可以在你啟動伺服器時使用--skip-show-database選項限制使用者對於他們沒用存取權限的資料庫使用SHOW
DATABASES和SHOW
TABLES。這有助於防止使用者找到關於它們不能存取的資料庫和表格的資訊。
ALTER權限能以不希望的方式使用。假定你想讓user1可以存取table1但不能存取tables2。一個擁有ALTER權限的使用者可以透過使用ALTER
TABLE將table2改名為table1來偷梁換柱。
當心GRANT權限。兩個由不同權限但都有GRANT權限的使用者可以讓彼此的權利更強大。
以上是MySQL安全性指南 (2)(轉)的內容,更多相關文章請關注PHP中文網(www.php.cn)!