作為一個MySQL的系統管理員,你有責任維護你的MySQL數據庫系統的數據安全性和完整性。本文主要主要介紹如何建立一個安全的MySQL系統,從系統內部和外部網絡兩個角度,為你提供一個指南。
本文主要考慮下列安全性有關的問題:
為什麼安全性很重要,你應該防范那些攻擊?
服務器面臨的風險(內部安全性),如何處理?
連接服務器的客戶端風險(外部安全性),如何處理?
MySQL管理員有責任保證數據庫內容的安全性,使得這些數據記錄只能被那些正確授權的用戶訪問,這涉及到數據庫系統的內部安全性和外部安全性。
內部安全性關心的是文件系統級的問題,即,防止MySQL數據目錄(DATADIR)被在服務器主機有賬號的人(合法或竊取的)進行攻擊。如果數據目錄內容的權限過分授予,使得每個人均能簡單地替代對應於那些數據庫表的文件,那麼確保控制客戶通過網絡訪問的授權表設置正確,對此毫無意義。
外部安全性關心的是從外部通過網絡連接服務器的客戶的問題,即,保護MySQL服務器免受來自通過網絡對服務器的連接的攻擊。你必須設置MySQL授權表(grant table),使得他們不允許訪問服務器管理的數據庫內容,除非提供有效的用戶名和口令。
下面就詳細介紹如何設置文件系統和授權表mysql,實現MySQL的兩級安全性。
一、內部安全性-保證數據目錄訪問的安全
MySQL服務器通過在MySQL數據庫中的授權表提供了一個靈活的權限系統。你可以設置這些表的內容,允許或拒絕客戶對數據庫的訪問,這提供了你防止未授權的網絡訪問對你數據庫攻擊的安全手段,然而如果主機上其他用戶能直接訪問數據目錄內容,建立對通過網絡訪問數據庫的良好安全性對你毫無幫助,除非你知道你是登錄MySQL服務器運行主機的唯一用戶,否則你需要關心在這台機器上的其他用戶獲得對數據目錄的訪問的可能性。
以下是你應該保護的內容:
數據庫文件。很明顯,你要維護服務器管理的數據庫的私用性。數據庫擁有者通常並且應該考慮數據庫內容的安全性,即使他們不想,也應該考慮時數據庫內容公開化,而不是通過糟糕的數據目錄的安全性來暴露這些內容。
日志文件。一般和更新日志必須保證安全,因為他們包含查詢文本。對日志文件有訪問權限的任何人可以監視數據庫進行過的操作。
更要重點考慮的日志文件安全性是諸如GRANT和SET PASSWord等的查詢也被記載了,一般和更新日志包含有敏感查詢的文本,包括口令(MySQL使用口令加密,但它在已經完成設置後才運用於以後的連接建立。設置一個口令的過程設計象GRANT或SET PASSWORD等查詢,並且這些查詢以普通文本形式記載在日志文件中)。如果一個攻擊者猶如日文件的讀權限,只需在日志文件上運行grep尋找諸如GRANT和PASSWord等詞來發現敏感信息。
顯然,你不想讓服務器主機上的其他用戶有數據庫目錄文件的寫權限,因為他們可以重寫你的狀態文件或數據庫表文件,但是讀權限也很危險。如果一個數據庫表文件能被讀取,偷取文件並得到MySQL本身,以普通文本顯示表的內容也很麻煩,為什麼?因為你要做下列事情:
在服務器主機上安裝你自己“特制”的MySQL服務器,但是有一個不同於官方服務器版本的端口、套接字和數據目錄。
運行mysql_install_db初始化你的數據目錄,這賦予你作為MySQL root用戶訪問你的服務器的權限,所以你有對服務器訪問機制的完全控制,它也建立一個test數據庫。
將對應於你想偷取得表文件拷貝到你服務器的數據庫目錄下的test目錄。
啟動你的服務器。你可以隨意訪問數據庫表,SHOW TABLES FROM test顯示你有一個偷來的表的拷貝,SELECT *顯示它們任何一個的全部內容。
如果你確實很惡毒,將權限公開給你服務器的任何匿名用戶,這樣任何人能從任何地方連接服務器訪問你的test數據庫。你現在將偷來的數據庫表公布於眾了。
在考慮一下,從相反的角度,你想讓別人對你這樣嗎?當然不!你可以通過在數據庫錄下執行ls -l命令確定你的數據庫是否包含不安全的文件和目錄。查找有“組”和“其他用戶”權限設置的文件和目錄。下面是一個不安全數據目錄的一部分列出:
% ls -l
total 10148
drwxrwxr-x 11 MySQLadm wheel 1024 May 8 12:20 .
drwxr-xr-x 22 root wheel 512 May 8 13:31 ..
drwx------ 2 mysqladm MySQLgrp 512 Apr 16 15:57 menagerIE
drwxrwxr-x 2 mysqladm wheel 512 Jan 25 20:40 MySQL
drwxrwxr-x 7 MySQLadm wheel 512 Aug 31 1998 sql-bench
drwxrwxr-x 2 MySQLadm wheel 1536 May 6 06:11 test
drwx------ 2 mysqladm MySQLgrp 1024 May 8 18:43 tmp
....
正如你看到的,有些數據庫有正確的權限,而其他不是。本例的情形是經過一段時間後的結果。較少限制的權限由在權限設置方面比更新版本更不嚴格的較早版本服務器設置的(注意更具限制的目錄menageria和tmp都有較近日期)。MySQL當前版本確保這些文件只能由運行服務器的用戶讀取。
讓我們來修正這些權限,使得只用服務器用戶可訪問它們。你的主要保護工具來自於由UNIX文件系統本身提供的設置文件和目錄屬主和模式的工具。下面是我們要做的:
進入該目錄
% cd DATADIR
設置所有在數據目錄下的文件屬主為由用於運行服務器的賬號擁有(你必須以root執行這步)。在本文使用mysqladm和MySQLgrp作為該賬號的用戶名和組名。你可以使用下列命令之一改變屬主:
# chown mysqladm.MySQLgrp .
# find . -follow -type d -print | xargs chown mysqladm.MySQLgrp
設置你的數據目錄和數據庫目錄的模式使得他們只能由MySQLadm讀取,這阻止其他用戶訪問你數據庫目錄的內容。你可以用下列命令之一以root或MySQLadm身份運行。
% chmod -R go-rwx .
% find . -follow -type d -print | xargs chmod go-rwx
數據目錄內容的屬主和模式為mysqladm設置。現在你應該保證你總是以MySQLadm用戶運行服務器,因為現在這是唯一由訪問數據庫目錄權限的用戶(除root)。
在完成這些設置後,你最終應該得到下面的數據目錄權限:
% ls -l
total 10148
drwxrwx--- 11 mysqladm MySQLgrp 1024 May 8 12:20 .
drwxr-xr-x 22 root wheel 512 May 8 13:31 ..
drwx------ 2 mysqladm MySQLgrp 512 Apr 16 15:57 menagerIE
drwx------ 2 mysqladm mysqlgrp 512 Jan 25 20:40 MySQL
drwx------ 7 mysqladm MySQLgrp 512 Aug 31 1998 sql-bench
drwx------ 2 mysqladm MySQLgrp 1536 May 6 06:11 test
drwx------ 2 mysqladm MySQLgrp 1024 May 8 18:43 tmp
....
二、外部安全性-保證網絡訪問的安全
MySQL的安全系統是很靈活的,它允許你以多種不同方式設置用戶權限。一般地,你可使用標准的SQL語句GRANT和REVOKE語句做,他們為你修改控制客戶訪問的授權表,然而,你可能由一個不支持這些語句的老版本的MySQL(在3.22.11之前這些語句不起作用),或者你發覺用戶權限看起來不是以你想要的方式工作。對於這種情況,了解MySQL授權表的結構和服務器如何利用它們決定訪問權限是有幫助的,這樣的了解允許你通過直接修改授權表增加、刪除或修改用戶權限,它也允許你在檢查這些表時診斷權限問題。
關於如何管理用戶賬號,見《MySQL的用戶管理》。而對GRANT和REVOKE語句詳細描述,見《MySQL參考手冊》。
2.1 MySQL授權表的結構和內容
通過網絡連接服務器的客戶對MySQL數據庫的訪問由授權表內容來控制。這些表位於MySQL數據庫中,並在第一次安裝MySQL的過程中初始化(運行MySQL_install_db腳本)。授權表共有5個表:user、db、host、tables_priv和columns_priv。
表1 user、db和host授權表結構
訪問范圍列
user db host
Host Host Host
User Db Db
PassWord User
數據庫/表權限列
Alter_priv Alter_priv Alter_priv
Create_priv Create_priv Create_priv
Delete_priv Delete_priv Delete_priv
Drop_priv Drop_priv Drop_priv
Index_priv Index_priv Index_priv
Insert_priv Insert_priv Insert_priv
References_priv References_priv References_priv
Select_priv Select_priv Select_priv
Update_priv Update_priv Update_priv
File_priv Grant_priv Grant_priv
Grant_priv
Process_priv
Reload_priv
Shutdown_priv
表2 tables_priv和columns_priv屬權表結構
訪問范圍列
tables_priv columns_priv
Host Host
Db Db
User User
Table_name Table_name
Column_name
權限列
Table_priv Column_priv
授權表的內容有如下用途:
user表
user表列出可以連接服務器的用戶及其口令,並且它指定他們有哪種全局(超級用戶)權限。在user表啟用的任何權限均是全局權限,並適用於所有數據庫。例如,如果你啟用了DELETE權限,在這裡列出的用戶可以從任何表中刪除記錄,所以在你這樣做之前要認真考慮。
db表
db表列出數據庫,而用戶有權限訪問它們。在這裡指定的權限適用於一個數據庫中的所有表。
host表
host表與db表結合使用在一個較好層次上控制特定主機對數據庫的訪問權限,這可能比單獨使用db好些。這個表不受GRANT和REVOKE語句的影響,所以,你可能發覺你根本不是用它。
tables_priv表
tables_priv表指定表級權限,在這裡指定的一個權限適用於一個表的所有列。
columns_priv表
columns_priv表指定列級權限。這裡指定的權限適用於一個表的特定列。
在“不用GRANT設置用戶”一節裡,我們再討論GRANT語句如何對修改這些表起作用,和你怎樣能通過直接修改授權表達到同樣的效果。
tables_priv和columns_priv表在MySQL 3.22.11版引進(與GRANT語句同時)。如果你有較早版本的MySQL,你的MySQL數據庫將只有user、db和host表。如果你從老版本升級到3.22.11或更新,而沒有tables_priv和columns_priv表,運行MySQL_fix_privileges_tables腳本創建它們。
MySQL沒有rows_priv表,因為它不提供記錄級權限,例如,你不能限制用戶於表中包含特定列值的行。如果你確實需要這種能力,你必須用應用編程來提供。如果你想執行建議的記錄級鎖定,你可用GET_LOCK()函數做到。
授權表包含兩種列:決定一個權限何時運用的范圍列和決定授予哪種權限的權限列。
2.1.1 授權表范圍列
授權表范圍列指定表中的權限何時運用。每個授權表條目包含User和Host列來指定權限何時運用於一個給定用戶從給定主機的連接。其他表包含附加的范圍列,如db表包含一個Db列指出權限運用於哪個數據庫。類似地,tables_priv和columns_priv表包含范圍字段,縮小范圍到一個數據庫中的特定表或一個表的特定列。
2.1.2 授權表權限列
授權表還包含權限列,他們指出在范圍列中指定的用戶擁有何種權限。由MySQL支持的權限如下表所示。該表使用GRANT語句的權限名稱。對於絕大多數在user、db和host表中的權限列的名稱與GRANT語句中有明顯的聯系。如Select_priv對應於SELECT權限。