MySQL性能调优与架构设计——第4章 MySQL安全管理
第4章 MySQL安全管理
前言
?? 對于任何一個企業(yè)來說,其數(shù)據(jù)庫系統(tǒng)中所保存數(shù)據(jù)的安全性無疑是非常重要的,尤其是公司的有些商業(yè)數(shù)據(jù),可能數(shù)據(jù)就是公司的根本,失去了數(shù)據(jù)的安全性,可能就是失去了公司的一切。本章將針對 MySQL 的安全相關(guān)內(nèi)容進(jìn)行較為詳細(xì)的介紹。
4.1 數(shù)據(jù)庫系統(tǒng)安全相關(guān)因素
一、外圍網(wǎng)絡(luò):
?? MySQL的大部分應(yīng)用場景都是基于網(wǎng)絡(luò)環(huán)境的,而網(wǎng)絡(luò)本身是一個充滿各種入侵危險的環(huán)境,所以要保護(hù)他的安全,在條件允許的情況下,就應(yīng)該從最外圍的網(wǎng)絡(luò)環(huán)境開始“布防”,因為這一層防線可以從最大范圍內(nèi)阻止可能存在的威脅。
?? 在網(wǎng)絡(luò)環(huán)境中,任意兩點之間都可能存在無窮無盡的“道路”可以抵達(dá),是一個真正“條條道路通羅馬”的環(huán)境。在那許許多多的道路中,只要有一條道路不夠安全,就可能被入侵者利用。當(dāng)然,由于所處的環(huán)境不同,潛在威脅的來源也會不一樣。有些MySQL所處環(huán)境是暴露在整個廣域網(wǎng)中,可以說是完全“裸露”在任何可以接入網(wǎng)絡(luò)環(huán)境的潛在威脅者面前。而有些MySQL是在一個環(huán)境相對小一些的局域網(wǎng)之內(nèi),相對來說,潛在威脅者也會少很多。處在局域網(wǎng)之內(nèi)的MySQL,由于有局域網(wǎng)出入口的網(wǎng)絡(luò)設(shè)備的基本保護(hù),相對于暴露在廣域網(wǎng)中要安全不少,主要威脅對象基本上控制在了可以接入局域網(wǎng)的內(nèi)部潛在威脅者,和極少數(shù)能夠突破最外圍防線(局域網(wǎng)出入口的安全設(shè)備)的入侵者。所以,盡可能的讓我們的MySQL處在一個有保護(hù)的局域網(wǎng)之中,是非常必要的。
二、主機(jī):
?? 有了網(wǎng)絡(luò)設(shè)備的保護(hù),我們的MySQL就足夠安全了么?我想大家都會給出否定的回答。因為即使我們局域網(wǎng)出入口的安全設(shè)備足夠的強(qiáng)大,可以攔截住外圍試圖入侵的所有威脅者,但如果威脅來自局域網(wǎng)內(nèi)部呢?比如局域網(wǎng)中可能存在被控制的設(shè)備,某些被控制的有權(quán)限接入局域網(wǎng)的設(shè)備,以及內(nèi)部入侵者等都仍然是威脅者。所以說,吉使在第一層防線之內(nèi),我們?nèi)匀淮嬖诎踩L(fēng)險,局域網(wǎng)內(nèi)部仍然會有不少的潛在威脅存在。
?? 這個時候就需要我們部署第二道防線“主機(jī)層防線”了。“主機(jī)層防線”主要攔截網(wǎng)絡(luò)(包括局域網(wǎng)內(nèi))或者直連的未授權(quán)用戶試圖入侵主機(jī)的行為。因為一個惡意入侵者在登錄到主機(jī)之后,可能通過某些軟件程序竊取到那些自身安全設(shè)置不夠健壯的數(shù)據(jù)庫系統(tǒng)的登入口令,從而達(dá)到竊取或者破壞數(shù)據(jù)的目的。如一個主機(jī)用戶可以通過一個未刪除且未設(shè)置密碼的無用戶名本地帳戶輕易登入數(shù)據(jù)庫,也可以通過MySQL初始安裝好之后就存在的無密碼的“root@localhost”用戶登錄數(shù)據(jù)庫并獲得數(shù)據(jù)庫最高控制權(quán)限。
?
? 非法用戶除了通過登入數(shù)據(jù)庫獲取(或者破壞)數(shù)據(jù)之外,還可能通過主機(jī)上面相關(guān)權(quán)限設(shè)置的漏洞,跳過數(shù)據(jù)庫而直接獲取MySQL數(shù)據(jù)(或者日志)文件達(dá)到竊取數(shù)據(jù)的目的,或者直接刪除數(shù)據(jù)(或者日志)文件達(dá)到破壞數(shù)據(jù)的目的。
三、數(shù)據(jù)庫:
? 通過第二道防線“主機(jī)層防線”的把守,我們又可以擋住很大一部分安全威脅者。但仍然可能有極少數(shù)突破防線的入侵者。而且即使沒有任何“漏網(wǎng)之魚”,那些有主機(jī)登入權(quán)限的使用者呢?是否真的就是完全可信任對象?No,我們不能輕易冒這個潛在風(fēng)險。對于一個有足夠安全意識的管理員來說,是不會輕易放任任何一個潛在風(fēng)險存在的。
? 這個時候,我們的第三道防線,“數(shù)據(jù)庫防線”就需要發(fā)揮他的作用了。“數(shù)據(jù)庫防線”也就是MySQL數(shù)據(jù)庫系統(tǒng)自身的訪問控制授權(quán)管理相關(guān)模塊。這道防線基本上可以說是MySQL的最后一道防線了,也是最核心最重要的防線。他首先需要能夠抵擋住在之前的兩層防線都沒有能夠阻攔住的所有入侵威脅,同時還要能夠限制住擁有之前二層防線自由出入但不具備數(shù)據(jù)庫訪問權(quán)限的潛在威脅者,以確保數(shù)據(jù)庫自身的安全以及所保存數(shù)據(jù)的安全。
? 之前的二層防線對于所有數(shù)據(jù)庫系統(tǒng)來說基本上區(qū)別不大,都存在著基本相同的各種威脅,不論是Oracle還是MySQL,以及任何其他的數(shù)據(jù)庫管理系統(tǒng),都需要基本一致的“布防”策略。但是這第三層防線,也就是各自自身的“數(shù)據(jù)庫防線”對于每個數(shù)據(jù)庫系統(tǒng)來說都存在較大的差異,因為每種數(shù)據(jù)庫都有各自不太一樣的專門負(fù)責(zé)訪問授權(quán)相關(guān)功能的模塊。不論是權(quán)限劃分還是實現(xiàn)方式都可能不太一樣。
? 對于MySQL來說,其訪問授權(quán)相關(guān)模塊主要是由兩部分組成。一個是基本的用戶管理模塊,另一個是訪問授權(quán)控制模塊。用戶管理模塊的功能相對簡單一些,主要是負(fù)責(zé)用戶登錄連接相關(guān)的基本權(quán)限控制,但其在安全控制方面的作用卻不比任何環(huán)節(jié)小。他就像 MySQL的一個“大門門衛(wèi)”一樣,通過校驗每一位敲門者所給的進(jìn)門“暗號”(登入口令),決定是否給敲門者開門。而訪問授權(quán)控制模塊則是隨時隨地檢查已經(jīng)進(jìn)門的訪問者,校驗他們是否有訪問所發(fā)出請求需要訪問的數(shù)據(jù)的權(quán)限。通過校驗者可順利拿到數(shù)據(jù),而未通過校驗的訪問者,只能收到“訪問越權(quán)了”的相關(guān)反饋。
? 上面的三道防線組成了如圖4-1所示的三道堅固的安全保護(hù)壁壘,就像三道堅固的城墻一樣保護(hù)這 MySQL 數(shù)據(jù)庫中的數(shù)據(jù)。只要保障足夠,基本很難有人能夠攻破這三道防線。
四、代碼:
?? 1、SQL語句相關(guān)安全因素:
? “SQL注入攻擊”這個術(shù)語我想大部分讀者朋友都聽說過了?指的就是攻擊者根據(jù)數(shù)據(jù)庫的SQL語句解析器的原理,利用程序中對客戶端所提交數(shù)據(jù)的校驗漏洞,從而通過程序動態(tài)提交數(shù)據(jù)接口提交非法數(shù)據(jù),達(dá)到攻擊者的入侵目的。
? “SQL注入攻擊”的破壞性非常的大,輕者造成數(shù)據(jù)被竊取,重者數(shù)據(jù)遭到破壞,甚至可能丟失全部的數(shù)據(jù)。如果讀者朋友還不是太清楚何為“SQL 注入攻擊”,建議通過互聯(lián)網(wǎng)搜索一下,可以得到非常多非常詳細(xì)的介紹及案例分析,這里有不做詳細(xì)介紹了。
?? 2、程序代碼相關(guān)安全因素:
?? 程序代碼如果權(quán)限校驗不夠仔細(xì)而存在安全漏洞,則同樣可能會被入侵者利用,達(dá)到竊取數(shù)據(jù)等目的。比如,一個存在安全漏洞的信息管理系統(tǒng),很容易就可能竊取到其他一些系統(tǒng)的登入口令。之后,就能堂而皇之的輕松登錄相關(guān)系統(tǒng)達(dá)到竊取相關(guān)數(shù)據(jù)的目的。甚至還可能通過應(yīng)用系統(tǒng)中保存不善的數(shù)據(jù)庫系統(tǒng)連接登錄口令,從而帶來更大的損失。
4.2 MySQL 權(quán)限系統(tǒng)介紹
4.2.1 權(quán)限系統(tǒng)簡介
?? MySQL的權(quán)限系統(tǒng)在實現(xiàn)上比較簡單,相關(guān)權(quán)限信息主要存儲在幾個被稱為 grant tables 的系統(tǒng)表中,即:mysql.User,mysql.db,mysql.Host,mysql.table_priv和mysql.column_priv。由于權(quán)限信息數(shù)據(jù)量比較小,而且訪問又非常頻繁,所以Mysql在啟動的時候,就會將所有的權(quán)限信息都Load到內(nèi)存中保存在幾個特定的結(jié)構(gòu)中。所以才有我們每次手工修改了權(quán)限相關(guān)的表之后,都需要執(zhí)行“FLUSH PRIVILEGES”命令重新加載MySQL的權(quán)限信息。當(dāng)然,如果我們通過GRANT,REVOKE或者DROP USER命令來修改相關(guān)權(quán)限,則不需要手工執(zhí)行FLUSH PRIVILEGES命令,因為通過GRANT,REVOKE或者DROP USER命令所做的權(quán)限修改在修改系統(tǒng)表的同時也會更新內(nèi)存結(jié)構(gòu)中的權(quán)限信息。在MySQL5.0.2或更高版本的時候,MySQL還增加了CREATE USER命令,以此創(chuàng)建無任何特別權(quán)限(僅擁有初始USAGE權(quán)限)的用戶,通過CREATE USER命令創(chuàng)建新了新用戶之后,新用戶的信息也會自動更新到內(nèi)存結(jié)構(gòu)中。所以,建議讀者一般情況下盡量使用GRANT,REVOKE,CREATE USER以及DROP USER命令來進(jìn)行用戶和權(quán)限的變更操作,盡量減少直接修改grant tables來實現(xiàn)用戶和權(quán)限變更的操作。
4.2.2? 權(quán)限授予與去除
?? 要為某個用戶授權(quán),可以使用GRANT命令,要去除某個用戶已有的權(quán)限則使用REVOKE命令。當(dāng)然,出了這兩者之外還有一種比較暴力的辦法,那就是直接更新grant tables系統(tǒng)表。當(dāng)給某個用戶授權(quán)的時候,不僅需要指定用戶名,同時還要指定來訪主機(jī)。如果在授權(quán)的時候僅指定用戶名,則MySQL會自動認(rèn)為是對'username'@'%'授權(quán)。要去除某個用戶的的權(quán)限同樣也需要指定來訪主機(jī)。
?? 可能有些時候我們還會需要查看某個用戶目前擁有的權(quán)限,這可以通過兩個方式實現(xiàn),首先是通過執(zhí)行“SHOW GRANTS FOR 'username'@'hostname'” 命令來獲取之前該用戶身上的所有授權(quán)。另一種方法是查詢grant tables里面的權(quán)限信息。
4.2.3 權(quán)限級別
MySQL中的權(quán)限分為五個級別,分別如下:
1、Global Level:
?? Global Level的權(quán)限控制又稱為全局權(quán)限控制,所有權(quán)限信息都保存在mysql.user表中。Global Level的所有權(quán)限都是針對整個mysqld的,對所有的數(shù)據(jù)庫下的所有表及所有字段都有效。如果一個權(quán)限是以Global Level來授予的,則會覆蓋其他所有級別的相同權(quán)限設(shè)置。比如我們首先給abc用戶授權(quán)可以UPDATE 指定數(shù)據(jù)庫如test的t表,然后又在全局級別REVOKE掉了abc用戶對所有數(shù)據(jù)庫的所有表的UPDATE權(quán)限。則這時候的abc用戶將不再擁有用對test.t表的更新權(quán)限。Global Level主要有如下這些權(quán)限(見表4-1):
??? 要授予Global Level的權(quán)限,則只需要在執(zhí)行GRANT命令的時候,用“*.*”來指定適用范圍是Global的即可,當(dāng)有多個權(quán)限需要授予的時候,也并不需要多次重復(fù)執(zhí)行GRANT命令,只需要一次將所有需要的權(quán)限名稱通過逗號(“,”)分隔開即可,如下:
??? root@localhost : mysql 05:14:35> GRANT SELECT,UPDATE,DELETE,INSERT ON *.* TO 'def'@'localhost';
??? Query OK, 0 rows affected (0.00 sec)
2、Database Level
??? Database Level是在Global Level之下,其他三個Level之上的權(quán)限級別,其作用域即為所指定整個數(shù)據(jù)庫中的所有對象。與Global Level的權(quán)限相比,Database Level主要少了以下幾個權(quán)限:CREATE USER,FILE,PROCESS,RELOAD,REPLICATION CLIENT,REPLICATION SLAVE,SHOW DATABASES,SHUTDOWN,SUPER和USAGE這幾個權(quán)限,沒有增加任何權(quán)限。之前我們說過Global Level的權(quán)限會覆蓋底下其他四層的相同權(quán)限,Database Level也一樣, 雖然他自己可能會被Global Level的權(quán)限設(shè)置所覆蓋,但同時他也能覆蓋比他更下層的Table,Column和Routine這三層的權(quán)限。
??? 如果要授予Database Level的權(quán)限,則可以有兩種實現(xiàn)方式:
??? 1、在執(zhí)行GRANT命令的時候,通過“database.*”來限定權(quán)限作用域為database整個數(shù)據(jù)庫,如下:
??? root@localhost : mysql 06:06:26> GRANT ALTER ON test.* TO 'def'@'localhost';
??? Query OK, 0 rows affected (0.00 sec)
??? root@localhost : test 06:12:45> SHOW GRANTS FOR def@localhost;
??? +------------------------------------------------------------------+
??? | Grants for def@localhost??????????????????????????????????????? |
??? +------------------------------------------------------------------+
??? | GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'def'@'localhost' |
??? | GRANT ALTER ON `test`.* TO 'def'@'localhost'??????????????????? |
??? +------------------------------------------------------------------+
??? 2、先通過USE命令選定需要授權(quán)的數(shù)據(jù)庫,然后通過“*”來限定作用域,這樣授權(quán)的作用域?qū)嶋H上就是當(dāng)前選定的整個數(shù)據(jù)庫。
??? root@localhost : mysql 06:14:05> USE test;
??? Database changed
??? root@localhost : test 06:13:10> GRANT DROP ON * TO 'def'@'localhost';
??? Query OK, 0 rows affected (0.00 sec)
??? root@localhost : test 06:15:26> SHOW GRANTS FOR def@localhost;
??? +------------------------------------------------------------------+
??? | Grants for def@localhost??????????????????????????????????????? |
??? +------------------------------------------------------------------+
??? | GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'def'@'localhost' |
??? | GRANT DROP, ALTER ON `test`.* TO 'def'@'localhost'????????????? |
??? +------------------------------------------------------------------+
??? 在授予權(quán)限的時候,如果有相同的權(quán)限需要授予多個用戶,我們也可以在授權(quán)語句中一??? 次寫上多個用戶信息,通過逗號(,)分隔開就可以了,如下:
??? root@localhost? :? mysql? 05:22:32>? grant? create? on? perf.*? to? 'abc'@'localhost','def'@'localhost';
??? Query OK, 0 rows affected (0.00 sec)
??? root@localhost : mysql 05:22:46> SHOW GRANTS FOR def@localhost;
??? +------------------------------------------------------------------+
??? | Grants for def@localhost???????????????????????????????????????? |
??? +------------------------------------------------------------------+
??? | GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'def'@'localhost' |
??? | GRANT DROP, ALTER ON `test`.* TO 'def'@'localhost'?????????????? |
??? | GRANT CREATE ON `perf`.* TO 'def'@'localhost'??????????????????? |
??? +------------------------------------------------------------------+
??? 3 rows in set (0.00 sec)
??? root@localhost : mysql 05:23:13> SHOW GRANTS FOR abc@localhost;
??? +------------------------------------------------------------------+
??? | Grants for abc@localhost???????????????????????????????????????? |
??? +------------------------------------------------------------------+
??? | GRANT CREATE ON `perf`.* TO 'abc'@'localhost'??????????????????? |
??? | GRANT SELECT ON `test`.* TO 'abc'@'localhost'??????????????????? |
??? +------------------------------------------------------------------+
??? 3 rows in set (0.00 sec)
3、Table Level
??? Database Level之下就是Table Level的權(quán)限了,Table Level的權(quán)限可以被Global Level和Database Level的權(quán)限所覆蓋,同時也能覆蓋Column Level和Routine Level的權(quán)限。
??? Table Level的權(quán)限作用范圍是授權(quán)語句中所指定數(shù)據(jù)庫的指定表。如可以通過如下語句給test數(shù)據(jù)庫的t1表授權(quán):
??? root@localhost? :? test? 12:02:15>? GRANT? INDEX? ON? test.t1? TO 'abc'@'%.jianzhaoyang.com';
??? Query OK, 0 rows affected, 1 warning (0.00 sec)
??? root@localhost : test 12:02:53> SHOW GRANTS FOR 'abc'@'%.jianzhaoyang.com';
??? +----------------------------------------------------------+
??? | Grants for abc@*.jianzhaoyang.com??????????????????????? |
??? +----------------------------------------------------------+
??? | GRANT USAGE ON *.* TO 'abc'@'%.jianzhaoyang.com'???????? |
??? | GRANT INDEX ON `test`.`t1` TO 'abc'@'%.jianzhaoyang.com' |
??? +----------------------------------------------------------+
??? 上面的授權(quán)語句在測試給test數(shù)據(jù)庫的t1表授予Table Level的權(quán)限的同時,還測試了將權(quán)限授予含有通配符“%”的所有“.jianzhaoyang.com”主機(jī)。其中的USAGE權(quán)限是每個用戶都有的最基本權(quán)限。
??? Table Level的權(quán)限由于其作用域僅限于某個特定的表,所以權(quán)限種類也比較少,僅有ALTER,CREATE,DELETE,DROP,INDEX,INSERT,SELECT UPDATE這八種權(quán)限。
4、Column Level
??? Column Level的權(quán)限作用范圍就更小了,僅僅是某個表的指定的某個(活某些)列。由于權(quán)限的覆蓋原則,Column Level的權(quán)限同樣可以被Global,Database,Table這三個級別的權(quán)限中的相同級別所覆蓋,而且由于Column Level所針對的權(quán)限和Routine Level的權(quán)限作用域沒有重合部分,所以不會有覆蓋與被覆蓋的關(guān)系。針對Column Level級別的權(quán)限僅有INSERT,SELECT和UPDATE這三種。Column Level的權(quán)限授權(quán)語句語法基本和Table Level差不多,只是需要在權(quán)限名稱后面將需要授權(quán)的列名列表通過括號括起來,如下:
??? root@localhost : test 12:14:46> GRANT SELECT(id,value) ON test.t2 TO
'abc'@'%.jianzhaoyang.com';
??? Query OK, 0 rows affected(0.00 sec)
??? root@localhost : test 12:16:49> SHOW GRANTS FOR 'abc'@'%.jianzhaoyang.com';
??? +-----------------------------------------------------------------------+
??? | Grants for abc@*.jianzhaoyang.com??????????????????????????????? |
??? +-----------------------------------------------------------------------+
??? | GRANT USAGE ON *.* TO 'abc'@'%.jianzhaoyang.com'???????????????? |
??? | GRANT SELECT (value, id) ON `test`.`t2` TO 'abc'@'%.jianzhaoyang.com' |
??? | GRANT INDEX ON `test`.`t1` TO 'abc'@'%.jianzhaoyang.com'???????? |
??? +-----------------------------------------------------------------------+
??? 注意:當(dāng)某個用戶在向某個表插入(INSERT)數(shù)據(jù)的時候,如果該用戶在該表中某列上面沒有INSERT權(quán)限,則該列的數(shù)據(jù)將以默認(rèn)值填充。這一點和很多其他的數(shù)據(jù)庫都有一些區(qū)別,是MySQL自己在SQL上面所做的擴(kuò)展。
5、Routine Level
??? Routine Level的權(quán)限主要只有EXECUTE和ALTER ROUTINE兩種,主要針對的對象是procedure和function這兩種對象,在授予Routine Level權(quán)限的時候,需要指定數(shù)據(jù)庫
和相關(guān)對象,如:
??? root@localhost : test 04:03:26> GRANT EXECUTE ON test.p1 to 'abc'@'localhost';
??? Query OK, 0 rows affected (0.00 sec)
??? 除了上面幾類權(quán)限之外,還有一個非常特殊的權(quán)限GRANT,擁有GRANT權(quán)限的用戶可以將自身所擁有的任何權(quán)限全部授予其他任何用戶,所以GRANT權(quán)限是一個非常特殊也非常重要的權(quán)限。GRANT權(quán)限的授予方式也和其他任何權(quán)限都不太一樣,通常都是通過在執(zhí)行GRANT授權(quán)語句的時候在最后添加WITH GRANT OPTION子句達(dá)到授予GRANT權(quán)限的目的。
??? 此外,我們還可以通過GRANT ALL 語句授予某個Level的所有可用權(quán)限給某個用戶, 如:
??? root@localhost : test 04:15:48> grant all on test.t5 to 'abc';
??? Query OK, 0 rows affected (0.00 sec)
??? root@localhost : test 04:27:39> grant all on perf.* to 'abc';
??? Query OK, 0 rows affected (0.00 sec)
??? root@localhost : test 04:27:52> show grants for 'abc';
??? +--------------------------------------------------+
??? | Grants for abc@%??????????????????????????? |
??? +--------------------------------------------------+
??? | GRANT USAGE ON *.* TO 'abc'@'%'???????????? |
??? | GRANT ALL PRIVILEGES ON `perf`.* TO 'abc'@'%'? |
??? | GRANT ALL PRIVILEGES ON `test`.`t5` TO 'abc'@'%' |
??? +--------------------------------------------------+
??? 在以上五個Level的權(quán)限中,Table、Column和Routine三者在授權(quán)中所依賴(或者引用)的對象必須是已經(jīng)存在的,而不像Database Level的權(quán)限授予,可以在當(dāng)前不存在該數(shù)據(jù)庫的時候就完成授權(quán)。
4.2.4 MySQL訪問控制實現(xiàn)原理
??? MySQL訪問控制實際上由兩個功能模塊共同組成,從第一篇的第二章架構(gòu)組成中可以看到,一個是負(fù)責(zé)“看守MySQL大門”的用戶管理模塊,另一個就是負(fù)責(zé)監(jiān)控來訪者每一個動作的訪問控制模塊。用戶管理模塊決定造訪客人能否進(jìn)門,而訪問控制模塊則決定每個客人進(jìn)門能拿什么不能拿什么。下面是一張MySQL中實現(xiàn)訪問控制的簡單流程圖(見圖4-2):
1、用戶管理
??? 我們先看看用戶管理模塊是如何工作的。在MySQL中,用戶訪問控制部分的實現(xiàn)比較簡單,所有授權(quán)用戶都存放在一個系統(tǒng)表中:mysql.user,當(dāng)然這個表不僅僅存放了授權(quán)用戶的基本信息,還存放有部分細(xì)化的權(quán)限信息。用戶管理模塊需要使用的信息很少,主要就是Host,User,Password這三項,都在mysql.user表中,如下:
??? sky@localhost : (none) 12:35:04> USE mysql;
??? Database changed
??? sky@localhost : mysql 12:35:08> DESC user;
??? 一個用戶要想訪問MySQL,至少需要提供上面列出的這三項數(shù)據(jù),MySQL才能判斷是否該讓他“進(jìn)門”。這三項實際上由量部分組成:訪問者來源的主機(jī)名(或者主機(jī)IP地址信息)和訪問者的來訪“暗號”(登錄用戶名和登錄密碼),這兩部分中的任何一個沒有能夠匹配上都無法讓看守大門的用戶管理模塊乖乖開門。其中Host信息存放的是MySQL允許所對應(yīng)的User的信任主機(jī),可以是某個具體的主機(jī)名(如:mytest)或域名(如:www.domain.com),也可以是以“%”來充當(dāng)通配符的某個域名集合(如:%.domain.com);也可以是一個具體的IP地址(如:1.2.3.4),同樣也可以是存在通配符的域名集合(如:1.2.3.%);還可以用“%”來代表任何主機(jī),就是不對訪問者的主機(jī)做任何限制。如以下設(shè)置:
root@localhost : mysql 01:18:12> SELECT host,user,password FROM user ORDER BY user;
??? 但是這里有一個比較特殊的訪問限制,如果要通過localhost訪問的話,必須要有一條專門針對localhost的授權(quán)信息,即使不對任何主機(jī)做限制也不行。如下例所示,存在def@%的用戶設(shè)置,但是如果不使用-h參數(shù)來訪問,則登錄會被拒絕,因為mysql在默認(rèn)情況下會連接localhost:
??? sky@sky:~$ mysql -u def -p
??? Enter password:
??? ERROR 1045 (28000): Access denied for user 'def'@'localhost' (using password: YES)
??? 但是當(dāng)通過-h參數(shù),明確指定了訪問的主機(jī)地址之后就沒問題了,如下:
??? sky@sky:~$ mysql -u def -p -h 127.0.0.1
??? Enter password:
??? Welcome to the MySQL monitor. Commands end with ; or \g.
??? Your MySQL connection id is 17
??? Server version: 5.0.51a-log Source distribution
??? Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
??? def@127.0.0.1 : (none) 01:26:04>
??? 如果我們有一條localhost的訪問授權(quán)則可以不使用-h參數(shù)來指定登錄host而連接默認(rèn)的localhost:
??? sky@sky:~$ mysql -u abc -p
??? Enter password:
??? Welcome to the MySQL monitor. Commands end with ; or \g.
??? Your MySQL connection id is 18
??? Server version: 5.0.51a-log Source distribution
??? Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
??? abc@localhost : (none) 01:27:19> exit
??? Bye
??? 如果MySQL正在運行之中的時候,我們對系統(tǒng)做了權(quán)限調(diào)整,那調(diào)整之后的權(quán)限什么時候會生效呢?
??? 我們先了解何時MySQL存放于內(nèi)存結(jié)構(gòu)中的權(quán)限信息被更新:FLUSH PRIVILEGES會強(qiáng)行讓MySQL更新Load到內(nèi)存中的權(quán)限信息;GRANT、REVOKE或者CREATE USER和DROP USER操作會直接更新內(nèi)存中的權(quán)限信息;重啟MySQL會讓MySQL完全從grant tables中讀取權(quán)限信息。
??? 那內(nèi)存結(jié)構(gòu)中的權(quán)限信息更新之后對已經(jīng)連接上的用戶何時生效呢?
??? 對于Global Level的權(quán)限信息的修改,僅僅只有更改之后新建連接才會用到,對于已經(jīng)連接上的session并不會受到影響。而對于Database Level的權(quán)限信息的修改,只有當(dāng)客戶端請求執(zhí)行了“USE database_name”命令之后,才會在重新校驗中使用到新的權(quán)限信息。所以有些時候如果在做了比較緊急的Global和Database這兩個Level的權(quán)限變更之后,可能需要通過“KILL”命令將已經(jīng)連接在MySQL中的session 殺掉強(qiáng)迫他們重新連接以使用更新后的權(quán)限。對于Table Level和Column Level的權(quán)限,則會在下一次需要使用到該權(quán)限的Query被請求的時候生效,也就是說,對于應(yīng)用來講,這兩個Level的權(quán)限,更新之后立刻就生效了,而不會需要執(zhí)行“KILL”命令。
2、訪問控制
?? 當(dāng)客戶端連接通過用戶管理模塊的驗證,可連接上MySQL Server之后,就會發(fā)送各種Query和Command給MySQL Server,以實現(xiàn)客戶端應(yīng)用的各種功能。當(dāng)MySQL 接收到客戶端的請求之后,訪問控制模塊是需要校驗該用戶是否滿足提交的請求所需要的權(quán)限。權(quán)限校驗過程是從最大范圍的權(quán)限往最小范圍的權(quán)限開始依次校驗所涉及到的每個對象的每個權(quán)限。
?? 在驗證所有所需權(quán)限的時候,MySQL首先會查找存儲在內(nèi)存結(jié)構(gòu)中的權(quán)限數(shù)據(jù),首先查找 Global Level 權(quán)限,如果所需權(quán)限在 Global Level 都有定義(GRANT或者REVOKE),則完成權(quán)限校驗(通過或者拒絕),如果沒有找到所有權(quán)限的定義,則會繼續(xù)往后查找Database Level 權(quán)限,進(jìn)行 Global Level 未定義的所需權(quán)限的校驗,如果仍然沒有能夠找到所有所需權(quán)限的定義,MySQL會繼續(xù)往更小范圍的權(quán)限定義域查找,也就是 Table Level,最后則是 Column Level 或者 Routine Level。
?? 下面我們就以客戶端通過abc@localhost連接后請求如下Query我為例:
?? SELECT id,name FROM test.t4 where status = 'deleted';
????????????????????????????? 圖4-3
?? 在前面我們了解到MySQL的grant tables有mysql.user,mysql.db,mysql.host,mysql.table_priv和mysql.column_priv這五個,我想除了mysql.host之外的四個都是非常容易理解的,每一個表針對MySQL中的一種邏輯對象,存放某一特定Level的權(quán)限,唯獨mysql.host稍有區(qū)別。我們現(xiàn)在就來看看mysql.host權(quán)限表到底在MySQL的訪問控制中充當(dāng)了一個什么樣的角色呢?
?? mysql.host在MySQL訪問控制模塊中所實現(xiàn)的功能比較特殊,和其他幾個grant tables不太一樣。首先是mysql.host中的權(quán)限數(shù)據(jù)不是(也不能)通過GRANT或者REVOKE來授予或者去除,必須通過手工通過INSERT、UPDATE和DELETE 命令來修改其中的數(shù)據(jù)。其次是其中的權(quán)限數(shù)據(jù)無法單獨生效,必須通過和mysql.db權(quán)限表的數(shù)據(jù)一起才能生效。而且僅當(dāng)mysql.db中存在不完整(某些場景下的特殊設(shè)置)的時候,才會促使訪問控制模塊再結(jié)合mysql.host中查找是否有相應(yīng)的補(bǔ)充權(quán)限數(shù)據(jù)實現(xiàn)以達(dá)到權(quán)限校驗的目的,就比如上圖中所示。在mysql.db中無法找到滿足權(quán)限校驗的所有條件的數(shù)據(jù)(db.User = 'abc' AND db.host = 'localhost' AND db.Database_name = 'test'),則說明在mysql.db中無法完成權(quán)限校驗,所以也不會直接就校驗db.Select_priv的值是否為'Y'。但是mysql.db中有db.User = 'abc' AND db.Database_name = 'test' AND db.host = '' 這樣一條權(quán)限信息存在,大家可能注意到了這條權(quán)限信息中的db.host中是空值,注意是空值而不是'%'這個通配符哦。當(dāng)MySQL注意到有這樣一條權(quán)限信息存在的時候,就該是mysql.host中所存放的權(quán)限信息出場的時候了。這時候,MySQL會檢測mysql.host中是否存在滿足如下條件的權(quán)限信息:host.Host = 'localhost' AND host.Db = 'test'。如果存在,則開始進(jìn)行Select_priv權(quán)限的校驗。由于權(quán)限信息存在于mysql.db和mysql.host兩者之中,而且是兩者信息合并才能滿足要求,所以Select_priv的校驗也需要兩表都為'Y'才能滿足要求,通過校驗。
?? 我們已經(jīng)清楚,MySQL的權(quán)限是授予“username@hostname”的,也就是說,至少需要用戶名和主機(jī)名二者才能確定一個訪問者的權(quán)限。又由于hostname可以是一個含有通配符的域名,也可以是一個含有通配符的IP地址段。那么如果同一個用戶有兩條權(quán)限信息,一條是針對特定域名的,另外一個是含有通配符的域名,而且前者屬于后者包含。這時候MySQL如何來確定權(quán)限信息呢?實際上MySQL永遠(yuǎn)優(yōu)先考慮更精確范圍的權(quán)限。在MySQL內(nèi)部會按照username和hostname作一個排序,對于相同username的權(quán)限,其host信息越接近訪問者的來源host,則排序位置越靠前,則越早被校驗使用到。而且,MySQL在權(quán)限校驗過程中,只要找到匹配的權(quán)限之后,就不會再繼續(xù)往后查找是否還有匹配的權(quán)限信息,而直接完成校驗過程。
?? 大家應(yīng)該也看到了在 mysql.user這個權(quán)限表中有 max_questions,max_updates,max_connections,max_user_connections這四列,前面三列是從MySQL4.0.2版本才開始有的,其功能是對訪問用戶進(jìn)行每小時所使用資源的限制,而最后的max_user_connections則是從MySQL5.0.3版本才開始有的,他和max_connections的區(qū)別是限制耽擱用戶的連接總次數(shù),而不是每小時的連接次數(shù)。而要使這四項限制生效,需要在創(chuàng)建用戶或者給用戶授
權(quán)的時候加上以下四種子句:
???????? max_questions? : WITH MAX_QUERIES_PER_HOUR n;
???????? max_updates??? : WITH MAX_UPDATES_PER_HOUR n;
???????? max_connections : WITH MAX_CONNECTIONS_PER_HOUR n;
???????? max_user_connections: MAX_USER_CONNECTIONS。
?? 四個子句可以同時使用,如:
?? “? WITH? MAX_QUERIES_PER_HOUR? 5000? MAX_CONNECTIONS_PER_HOUR? 10 MAX_USER_CONNECTIONS 10000”。
4.3 MySQL 訪問授權(quán)策略
?? 在我們了解了影響數(shù)據(jù)庫系統(tǒng)安全的相關(guān)因素以及MySQL權(quán)限系統(tǒng)的工作原理之后,就需要為我們的系統(tǒng)設(shè)計一個安全合理的授權(quán)策略。我想,每個人心里都清楚,要想授權(quán)最簡單最簡單方便,維護(hù)工作量最少,那自然是將所有權(quán)限都授予所有的用戶來的最簡單方便了。但是,我們大家肯定也都知道,一個用戶所用有的權(quán)限越大,那么他給我們的系統(tǒng)所帶來的潛在威脅也就越大。所以,從安全方面來考慮的話,權(quán)限自然是授予的越小越好。一個有足夠安全意識的管理員在授權(quán)的時候,都會只授予必要的權(quán)限,而不會授予任何多余的權(quán)限。既然我們這一章是專門討論安全的,那么我們現(xiàn)在也就從安全的角度來考慮如何設(shè)計一個更為安全合理的授權(quán)策略。
?? 首先,需要了解來訪主機(jī)。
?? 由于MySQL數(shù)據(jù)庫登錄驗證用戶的時候是出了用戶名和密碼之外,還要驗證來源主機(jī)。所以我們還需要了解每個用戶可能從哪些主機(jī)發(fā)起連接。當(dāng)然,我們也可以通過授權(quán)的時候直接通過“%”通配符來給所有主機(jī)都有訪問的權(quán)限,但是這樣作就違背了我們安全策略的原則,帶來了潛在風(fēng)險,所以并不可取。尤其是在沒有局域網(wǎng)的防火墻保護(hù)的情況下,更是不能輕易允許可以從任何主機(jī)登錄的用戶存在。能通過具體主機(jī)名或者IP地址指定的盡量通過使用具體的主機(jī)名和IP地址來限定來訪主機(jī),不能用具體的主機(jī)名或者IP地址限定的也需要用盡可能小的通配范圍來限定。
?? 其次,了解用戶需求。
?? 既然是要做到僅授予必要的權(quán)限,那么我們必須了解每個用戶所擔(dān)當(dāng)?shù)慕巧?#xff0c;也就是說,我們需要充分了解每個用戶需要連接到數(shù)據(jù)庫上完成什么工作。了解該用戶是一個只讀應(yīng)用的用戶,還是一個讀寫都有的帳戶;是一個備份作業(yè)的用戶還是一個日常管理的帳戶;是只需要訪問特定的某個(或者某幾個)數(shù)據(jù)庫(Schema),還是需要訪問所有的數(shù)據(jù)庫。只有了解了需要做什么,才能準(zhǔn)確的了解需要授予什么樣的權(quán)限。因為如果權(quán)限過低,會造成工作無法正常完成,而權(quán)限過高,則存在潛在的安全風(fēng)險。
?? 再次,要為工作分類。
?? 為了做到各司其職,我們需要將需要做的工作分門別類,不同類別的工作使用不同的用戶,做好用戶分離。雖然這樣可能會帶來管理成本方面的部分工作量增加,但是基于安全方面的考慮,這部分管理工作量的增加是非常值得的。而且我們所需要做的用戶分離也只是一個適度的分離。比如將執(zhí)行備份工作、復(fù)制工作、常規(guī)應(yīng)用訪問、只讀應(yīng)用訪問和日常管理工作分別分理出單獨的特定帳戶來授予各自所需權(quán)限。這樣,既可以讓安全風(fēng)險盡量降低,也可以讓同類同級別的相似權(quán)限合并在一起,不互相交織在一起。對于PROCESS,FILE和SUPER這樣的特殊權(quán)限,僅僅只有管理類帳號才需要,不應(yīng)該授予其他非管理帳號。
?? 最后,確保只有絕對必要者擁有GRANT OPTION 權(quán)限。
?? 之前在權(quán)限系統(tǒng)介紹的時候我們已經(jīng)了解到GRANT OPTION權(quán)限的特殊性,和擁有該權(quán)限之后的潛在風(fēng)險,所以在這里也就不再累述了。總之,為了安全考慮,擁有GRANT OPTION權(quán)限的用戶越少越好,盡可能只讓擁有超級權(quán)限的用戶才擁有GRANT OPTION權(quán)限。
4.4 安全設(shè)置注意事項
?? 在前面我們了解了影響數(shù)據(jù)庫系統(tǒng)安全的幾個因素,也了解了MySQL權(quán)限系統(tǒng)的相關(guān)原理和實現(xiàn),這一節(jié)我們將針對這些因素進(jìn)行一些基本的安全設(shè)置討論,了解一些必要的注意事項。
?? 首先,自然是最外圍第一層防線的網(wǎng)絡(luò)方面的安全。
?? 我們首先要確定我們所維護(hù)的MySQL環(huán)境是否真的需要提供網(wǎng)絡(luò)服務(wù)?是否可以使我們的MySQL僅僅提供本地訪問,而禁止網(wǎng)絡(luò)服務(wù)?如果可以,那么我們可以在啟動MySQL的時候通過使用“--skip-networking”參數(shù)選項,讓MySQL不通過TCP/IP監(jiān)聽網(wǎng)絡(luò)請求,而僅僅通過命名管道或共享內(nèi)存(在Windows中)或Unix套接字文件(在Unix中)來和客戶端連接交互。
?? 當(dāng)然,在本章最開始的時候,我們就已經(jīng)討論過,由于MySQL數(shù)據(jù)庫在大部分應(yīng)用場景中都是在網(wǎng)絡(luò)環(huán)境下,通過網(wǎng)絡(luò)連接提供服務(wù)。所以我們只有少部分應(yīng)用能通過禁用網(wǎng)絡(luò)監(jiān)聽來斷絕網(wǎng)絡(luò)訪問以保持安全,剩下的大部分還是需要通過其他方案來解決網(wǎng)絡(luò)方面存在的潛在安全威脅。
?? 使用私有局域網(wǎng)絡(luò)。我們可以通過使用私有局域網(wǎng)絡(luò),通過網(wǎng)絡(luò)設(shè)備,統(tǒng)一私有局域網(wǎng)的出口,并通過網(wǎng)絡(luò)防火墻設(shè)備控制出口的安全。
?? 使用SSL加密通道。如果我們的數(shù)據(jù)對保密要求非常嚴(yán)格,可以啟用MySQL提供的SSL訪問接口,將傳輸數(shù)據(jù)進(jìn)行加密。使網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)即使被截獲,也無法輕易使用。
?? 訪問授權(quán)限定來訪主機(jī)信息。在之前的權(quán)限系統(tǒng)介紹中我們已經(jīng)了解到MySQL的權(quán)限信息是針對用戶和來訪主機(jī)二者結(jié)合定位的。所以我們可以在授權(quán)的時候,通過指定主機(jī)的主機(jī)名、域名或者IP地址信息來限定來訪主機(jī)的范圍。
?? 其次,在第二層防線主機(jī)上面也有以下一些需要注意的地方。
?? OS安全方面。關(guān)閉MySQL Server主機(jī)上面任何不需要的服務(wù),這不僅能從安全方面減少潛在隱患,還能減輕主機(jī)的部分負(fù)擔(dān),盡可能提高性能。使用網(wǎng)絡(luò)掃描工具(如nmap等)掃描主機(jī)端口,檢查除了MySQL需要監(jiān)聽的端口3306(或者自定義更改后的某個端口)之外,還有哪些端口是打開正在監(jiān)聽的,并去掉不必要的端口。嚴(yán)格控制OS帳號的管理,以防止帳號信息外泄,尤其是root和mysql帳號。對root和mysql等對mysql的相關(guān)文件有特殊操作權(quán)限的OS帳號登錄后做出比較顯眼的提示,并在Terminal的提示信息中輸出當(dāng)前用戶信息,以防止操作的時候經(jīng)過多次用戶切換后出現(xiàn)人為誤操作。
?? 用非root用戶運行MySQL。這在MySQL官方文檔中也有非常明顯的提示,提醒用戶不要使用root用戶來運行MySQL。因為如果使用root用戶運行MySQL,那么mysqld的進(jìn)程就會擁有root用戶所擁有的權(quán)限,任何具有FILE權(quán)限的MySQL用戶就可以在MySQL中向系統(tǒng)中的任何位置寫入文件。當(dāng)然,由于MySQL不接受操作系統(tǒng)層面的認(rèn)證,所以任何操作系統(tǒng)層級的帳號都不能直接登錄MySQL,這一點和Oracle的權(quán)限認(rèn)證有些區(qū)別,所以在這一方面我們可以減少一些安全方面的顧慮。
?? 文件和進(jìn)程安全。合理設(shè)置文件的權(quán)限屬性,MySQL相關(guān)的數(shù)據(jù)和日志文件和所在的文件夾屬主和所屬組都設(shè)置為mysql,且禁用其他所有用戶(除了擁有超級權(quán)限的用戶,如root)的讀寫權(quán)限。以防止數(shù)據(jù)或者日志文件被竊取或破壞。因為如果一個用戶對MySQL的數(shù)據(jù)文件有讀取權(quán)限的話,可以很容易將數(shù)據(jù)復(fù)制。binlog文件也很容易還原整個數(shù)據(jù)庫。而如果有寫權(quán)限的話就更糟了,因為有了寫權(quán)限,數(shù)據(jù)或者日志文件就有被破壞或者刪除的風(fēng)險存在。保護(hù)好socket文件的安全,盡量不要使用默認(rèn)的位置(如/tmp/mysql.sock),以防止被有意或無意的刪除。
?? 確保MySQL Server所在的主機(jī)上所必要運行的其他應(yīng)用或者服務(wù)足夠安全,避免因為其他應(yīng)用或者服務(wù)存在安全漏洞而被入侵者攻破防線。
?? 在OS層面還有很多關(guān)于安全方面的其他設(shè)置和需要注意的地方,但考慮到篇幅問題,這里就不做進(jìn)一步分析了,有興趣的讀者可以參考各種不同OS在安全方面的專業(yè)書籍。
?? 再次,就是最后第三道防線MySQL自身方面的安全設(shè)置注意事項。
?? 到了最后這道防線上,我們有更多需要注意的地方。
?? 用戶設(shè)置。我們必須確保任何可以訪問數(shù)據(jù)庫的用戶都有一個比較復(fù)雜的內(nèi)容作為密碼,而不是非常簡單或者比較有規(guī)律的字符,以防止被使用字典破解程序攻破。在 MySQL初始安裝完成之后,系統(tǒng)中可能存在一個不需要任何密碼的root用戶,有些版本安裝完成之后還會存在一個可以通過localhost登錄的沒有用戶名和密碼的帳號。這些帳號會給系統(tǒng)帶來極大的安全隱患,所以我們必須在正式啟用之前盡早刪除,或者設(shè)置一個比較安全的密碼。對于密碼數(shù)據(jù)的存放,也不要存放在簡單的文本文件之中,而應(yīng)該使用專業(yè)密碼管理軟件來管理(如KeePass)。同時,就像之前在網(wǎng)絡(luò)安全注意事項部分講到的那樣,盡可能為每一個帳戶限定一定范圍的可訪問主機(jī)。尤其是擁有超級權(quán)限的MySQL root帳號,盡量確保只能通過localhost訪問。
?? 安全參數(shù)。在MySQL官方參考手冊中也有說明,不論是從安全方面考慮還是從性能以及功能穩(wěn)定性方面考慮,不需要使用的功能模塊盡量都不要啟用。例如,如果不需要使用用戶自定義函數(shù),就不要在啟動的時候使用“--allow-suspicious-udfs”參數(shù)選項,以防止被別有居心的潛在威脅者利用此功能而對MySQL的安全造成威脅;不需要從本地文件中Load數(shù)據(jù)到數(shù)據(jù)庫中,就使用“--local-infile=0”禁用掉可以從客戶端機(jī)器上Load文件到數(shù)據(jù)庫中;使用新的密碼規(guī)則和校驗規(guī)則(不要使用“--old-passwords”啟動數(shù)據(jù)庫),這項功能是為了兼容舊版本的密碼校驗方式的,如無額數(shù)必要,不要使用該功能,舊版本的密碼加密方式要比新的方式在安全方面弱很多。
?? 除了以上這三道防線,我們還應(yīng)該讓連接MySQL數(shù)據(jù)庫的應(yīng)用程序足夠安全,以防止入侵者通過應(yīng)用程序中的漏洞而入侵到應(yīng)用服務(wù)器,最終通過應(yīng)用程序中的數(shù)據(jù)庫相關(guān)關(guān)配置而獲取數(shù)據(jù)庫的登錄口令。
4.5 小結(jié)
? 安全無小事,一旦安全出了問題一切都完了。數(shù)據(jù)的安全是一個企業(yè)安全方面最核心最重要的內(nèi)容,只有保障的數(shù)據(jù)的安全,企業(yè)才有可能真正“安全”。希望這一章 MySQL 安全方面的內(nèi)容能夠?qū)Ω魑蛔x者在構(gòu)筑安全的企業(yè)級 MySQL 數(shù)據(jù)庫系統(tǒng)中帶來一點幫助。
摘自:《MySQL性能調(diào)優(yōu)與架構(gòu)設(shè)計》簡朝陽
轉(zhuǎn)載請注明出處:
作者:JesseLZJ
出處:http://jesselzj.cnblogs.com
轉(zhuǎn)載于:https://www.cnblogs.com/jesselzj/p/4713400.html
總結(jié)
以上是生活随笔為你收集整理的MySQL性能调优与架构设计——第4章 MySQL安全管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国产与第三方库FFmpeg SDK
- 下一篇: (一个)AngularJS获取贴纸Hel