1. 程式人生 > >MySql(五):MySQL資料庫安全管理

MySql(五):MySQL資料庫安全管理

一、前言

  1. 對於任何一個企業來說,其資料庫系統中所儲存資料的安全性無疑是非常重要的,尤其是公司的有些商業資料,可能資料就是公司的根本。
  2. 失去了資料,可能就失去了一切
  3. 本章將針對mysql的安全相關內容進行較為詳細的介紹。

二、資料庫系統安全相關因素

1、外圍網路

讓我們的mysql處在一個有保護的區域網之中,而不是置於開發的公網中。

2、主機

第二層防線“主機層防線”,“主機層防線“主要攔截網路(包括區域網)或者直連的未授權使用者試圖入侵主機的行為。

 

3、資料庫

第三道防線“資料庫防線”,也就是mysql資料庫系統自身的訪問控制授權管理相關模組。

這道防線基本上可以說是mysql的最後一道防線了,也是最核心最重要的防線

之前的兩層防線對於所有資料庫系統來說基本上區別不大,都存在者基本相同的各種威脅,不論是Oracle還是mysql,以及其他的資料庫管理系統,都需要基本一致的“佈防”策略。

但是這第三層防線,也就是各自自身的“資料庫防線”對於每個資料庫系統來說都存在較大差異,因為每種資料庫都有各自不太一樣的專門負責訪問授權相關的模組。不論是許可權劃分還是實現方式都可能不太一樣。

MySql的訪問授權相關模組主要是由兩部分組成,一個是基本的使用者管理模組;另一個是訪問授權控制模組

  1. 使用者管理模組相對簡單,主要是負責使用者登陸連線相關的基本許可權控制,但其在安全控制方面的作用不比任何環節小。他就像mysql的一個“大門門衛”一樣,通過校驗每一位敲門者所給的進門“暗號”(登入口令),決定是非給敲門者開門。
  2. 訪問控制模組則是隨時隨地檢查已經進門的訪問者,校驗他們是否有訪問所發出請求需要訪問的資料的許可權。通過校驗者可以順利拿到資料,而未通過校驗的訪問者,只能收到“訪問越權”的相關反饋。

4、程式碼

1)SQL語句相關安全因素

“SQL注入攻擊”指的就是攻擊者根據資料庫的SQL語句解析器的原理,利用程式中對客戶端所提交資料的校驗漏洞,從而通過程式動態提交資料介面提交非法資料,達到攻擊者的入侵目的。

“SQL注入攻擊“的破壞性非常大,輕者造成資料被竊取,重者資料遭到破壞,甚至可能丟失全部的資料。

2)程式程式碼相關安全因素

程式程式碼如果許可權校驗不夠仔細而存在安全漏洞,則同樣可能會被入侵者利用,達到竊取資料等目的。

比如一個存在安全漏洞的資訊管理系統,很容易就可能竊取到其他一些系統的登入口令。之後,就能堂而皇之的輕鬆登陸到其他相關係統達到竊取相關資料的目的。甚至還可能通過應用系統中儲存不善的資料庫系統連線登陸口令,從而帶來更大的損失。

三、MySQL許可權系統介紹

1、許可權系統簡介

msql的許可權系統在實現上比較簡單,相關許可權資訊主要儲存在幾個被稱為grant tables的系統表中,即:mysql.User,mysql.db,mysql.Host,mysql.table_priv和mysql.column_priv。

由於許可權資訊資料量比較小,而且訪問比較頻繁,所以mysql在啟動的時候,就會將所有的許可權資訊都load到記憶體中儲存在幾個特定的結構中

所以才有了我們每次手工修改了許可權相關的表之後,都需要執行“flush privileges”命令重新載入mysql的許可權資訊

當然,如果我們通過grant、revoke或者drop user命令來修改相關許可權,則不需要手工執行“flush privileges”命令,因為在使用grant等來修改系統表的同時,也會修改記憶體結構中的許可權資訊。

在mysql5.0.2或更高版本的時候,mysql還增加了CREATE USER命令,以此建立無任何特別許可權(僅擁有初始USAGE許可權)的使用者,通過CREATE USER命令建立了新使用者後,新使用者的資訊也會自動更新到記憶體結構中。

所以,建議讀者一般情況下儘量使用GRANT、REVOKE、CREATE USER以及DROP USER命令來進行使用者和許可權的變更操作,儘量減少直接修改grant tables來實現使用者和許可權變更的操作。

2、許可權授予與去除

要為某個使用者授權,可以使用GRANT命令,要去除某個使用者已有的許可權則使用REVOKE命令。

當然除了這兩個命令之外,還有一種比較暴力的辦法,那就是直接更新grant tables系統表

給某個使用者授權的時候,不僅需要指定使用者名稱,同時還要指定來訪主機

如果授權的時候僅指定使用者名稱,則mysql會自動認為是對“[email protected]%”授權。

要去除某個使用者的許可權同樣也需要指定來訪主機

可能有些時候我們還需要檢視某個使用者目前擁有的許可權,這可以通過兩個方式實現,首先是通過執行“show grants for 'username'@'hostname'”命令來獲取之前該使用者身上的所有授權。另一種方法是查詢grant tables裡邊的許可權資訊

3、許可權級別

1)Global Level

  1. Global Level的許可權控制也叫全域性許可權控制,所有許可權資訊都儲存在mysql.user表中。
  2. Global Level的所有許可權都是針對整個mysqld的,對所有的資料庫下的所有表及所有欄位都有效。
  3. 如果一個許可權是以Global Level來授予的,則會覆蓋其他所有級別的相同許可權設定。
  4. 比如我們首先給abc使用者授權可以update指定資料庫如test的t表,然後又在全域性級別REVOKE掉了abc使用者對所有資料庫的所有表的UPDATE許可權,那麼這時候的abc使用者將不再擁有對test.t表的更新許可權。
  5. 要授予Global Level的許可權,則只需要在執行GRANT命令的時候,用“*.*”來指定適用範圍是Global的即可,當有多個許可權需要授予的時候,也並不需要多次重複執行GRANT命令,只需要一次將所有需要的許可權名稱通過逗號(“,”)隔開即可,如:GRANT SELECT,UPDATE,DELETE,INSERT ON *.* TO 'def'@'localhost';

2)Database Level

  1. Database Level是在Global Level之下,其他三個Level之上的許可權級別,其作用域即為所指定整個資料庫中的所有物件。
  2. 與Global Level相比,Database Level主要少了以下幾個許可權:CREATE USER、FILE、PROCESS、RELOAD、REPLICATION CLIENT、REPLICATION SLAVE、SHOW DATABASES、SHUTDOWN、SUPER和USAGE這幾個許可權,沒有增加任何許可權。
  3. 之前我們說Global Level的許可權會覆蓋底下其他四層的相同許可權,Database Level也一樣,雖然他可能被Global Level的許可權所覆蓋,但同時他也能覆蓋比他更下層的Table、Column和Routine這三層的許可權。
  4. 如果要授予Database Level的許可權,則可以有兩種實現方式:
    a.在執行GRANT命令的時候,通過“database.*”來限定許可權作用域為database整個資料庫:GRANT ALTER ON test.* TO 'def'@'localhost';
    b.先通過USE命令選定需要授權的資料庫,然後通過“*”來限定作用域,這樣授權的作用域實際上就是當前選定的資料庫
  5. 在授予許可權的時候,如果有相同的許可權需要授予多個使用者,我們也可以在授權語句中一次寫上多個使用者資訊,用逗號分隔開就可以了,如:grant create on perf.* to 'abc'@'localhost','def'@'localhost';

3)Table Level

  1. Database Level之下就是Table Level的許可權了,Table Level的許可權可以被Global Level 和Database Level的許可權所覆蓋,同時也能覆蓋Column Level 和Routine Level 的許可權。
  2. Table Level 的許可權作用範圍是授權語句中所指定資料庫的指定表。如可以通過如下語句給test資料庫的t1表授權:GRANT INDEX ON test.t1 TO 'abc'@'%.jianzhaoyang.com';
  3. Table Level的許可權由於其作用域僅限於某個特定的表,所以許可權種類也比較少,僅有ALTER、CREATE、DELETE、DROP、INDEX、INSERT、SELECT、UPDATE這八種許可權。

4)Column Level

  1. Column Level的許可權作用範圍就更小了,僅僅是某個表的指定的某個列。
  2. 由於許可權覆蓋的原則,Column Level的許可權同樣可以被Global、Database、Table這三個級別的許可權中的相同級別所覆蓋,而且由於Column Level所針對的許可權和Routine Level的許可權作用域沒有重合部分,所以不會有覆蓋與被覆蓋的關係。
  3. Column Level的許可權只有INSERT、SELECT和UPDATE這三種。
  4. Column Level的許可權授權語句語法基本和Table Level差不多,只是需要在許可權名稱後面將需要授權的列名列表通過括號括起來:GRANT SELECT(id,value) ON test.t2 TO 'abc'@'%.jianzhaoyang.com';
  5. 當某個使用者在向某個表插入資料的時候,如果該使用者在該表中某列上面沒有INSERT許可權,則該列的資料將以預設值填充。這一點和很多其他的資料庫有一些區別,是mysql自己在SQL上面的擴充套件。

5)Routine Level

  1. Routine Level的許可權主要只有EXECUTE和ALTER ROUTINE兩種,主要的針對的物件是procedure 和function這兩種物件。
  2. 在授予Routine Level許可權的時候,需要指定資料庫和相關物件,如:GRANT EXECUTE ON test.p1 to 'abc'@'localhost';

6)GRANT許可權

  1. 除了上述幾類許可權外,還有一個非常特殊的許可權GRANT,擁有GRANT許可權的使用者可以將自身所擁有的任何許可權全部授予其他任何使用者,所以GRANT許可權是一個非常特殊也非常重要的許可權。
  2. GRANT許可權的授予方式也和其他任何許可權都不太一樣。
  3. 通常是通過在執行GRANT授權語句的時候在最後新增WITH GRANT OPTION子句達到授予GRANT許可權的目的。
  4. 另外,我們還可以通過GRANT ALL語句授予某個Level的所有可用許可權給某個使用者,如: grant all on test.t5 to 'abc';
  5. 以上五個Level的許可權中,Table、Column和Routine三者在授權中所依賴(或引用的)物件必須是已經存在的,而不像Database Level的許可權授予,可以在當前不存在該資料庫的時候完成授權。

4、MySQL訪問控制實現原理

  1. MySQL的訪問控制實際上由兩個功能模組共同組成,一個是負責“看守mysql大門”的使用者管理模組,另一個就是負責監控來訪者每一個動作的訪問控制模組
  2. 使用者管理模組決定造訪客人能否進門,而訪問控制模組則決定每個客人進門能拿什麼不能拿什麼。
  3. mysql中實現簡單訪問控制的流程圖如下:

     

  4. 使用者管理:

    (1)在mysql中,使用者訪問控制部分的實現比較簡單,所有授權使用者都存放在一個系統表中:mysql.user,當然這個表不僅存放了授權使用者的基本資訊,還存放有部分細化的許可權資訊。
    (2)使用者管理模組需要使用的資訊很少,主要就是Host、User、Password這三項,都在mysql.user表中
    (3)一個使用者想要訪問mysql,至少需要提供上面列出的三項資料,mysql才能判斷是否該讓它進門。
    (4)這三項實際是由兩部分組成:來訪者來源的主機名(或主機IP地址資訊)和訪問者的來訪“暗號”(登陸使用者名稱和登陸密碼),這兩部分中的任何一個沒有能夠匹配上都無法讓看守大門的使用者管理模組乖乖開門。
    (5)其中Host資訊存放的是mysql允許所對應的User的信任主機,可以是某個具體的主機名或域名,也可以是用“%”來充當萬用字元的某個域名集合,也可以是一個具體的IP地址,同樣也可以是存在萬用字元的域名集合,還可以用“%”來代表任何主機,就是不對訪問者的主機做任何限制。

  5. 訪問控制:

    (1)當客戶端連線通過使用者管理模組的驗證,可連線上mysql server之後,就會發送各種Query和Command給mysql server,以實現客戶端應用的各種功能。
    (2)當mysql接收到客戶端的請求之後,訪問控制模組是需要校驗該使用者是否滿足提交的請求所需要的許可權。
    (3)許可權校驗過程是從最大範圍往最小範圍的許可權開始依次校驗所涉及到的每個物件的每個許可權。
    (4)在驗證所需許可權的時候,mysql首先會查詢儲存在記憶體結構中的許可權資料,首先查詢Global Level許可權,如果所需許可權在Global Level都有定義(GRANT或REVOKE),則完成許可權校驗(通過或者拒絕);
    (5)如果沒有找到所有許可權的定義,則會繼續查詢Database Level的許可權,進行Global Level未定義的所需許可權的校驗,如果仍然沒有找到所有所需許可權的定義,則會繼續往更小範圍的許可權定義域查詢,也就是Table Level、Column Level或者Routine Level。
    (6)在前面我們瞭解到mysql的grant tables有mysql.user、mysql.db、mysql.host、mysql.table_priv和mysql.column_priv這五個。
    (7)我想除了mysql.host之外的四個都非常容易理解,每一個表都針對mysql的一種邏輯物件,存放某一特定Leve的許可權,唯獨mysql.host稍有區別。
    (8)我們來看看mysql.host許可權表在mysql訪問控制中充當了什麼樣的角色?
    【1】mysql.host在mysql訪問控制模組中所實現的功能比較特殊,和其他幾個grant tables不太一樣。
    【2】首先mysql.host中的許可權資料不是通過GRANT或REVOKE來授予或者去除,而是必須手工通過INSESRT、UPDATE和DELETE命令來修改其中的資料。
    【3】其次是其中的許可權資料無法單獨生效,必須通過和mysql.db許可權表的資料一起才能生效。
    【4】而且僅當mysql.db總存在不完整的時候,才會促使訪問控制模組再結合mysql.host中查詢是否有相應的補充許可權資料實現以達到許可權校驗的目的。
    【5】在mysql.db中無法找到滿足許可權校驗的所有條件的資料,則說明在mysql.db中無法完成許可權校驗,所以也不會直接校驗db.select_priv的值是否是Y。
    (9)mysql的許可權授予至少需要使用者名稱和主機名二者才能確定一個訪問者的許可權。
    (10)mysql如何確定許可權資訊?實際上,mysql永遠優先考慮更精確範圍的許可權。
    (11)在mysql內部會按照username和hostname做一個排序,對於相同username的許可權,其host資訊越接近訪問者的來源host,則排序位置越靠前,則越早被校驗使用到。
    (12)而且mysql在許可權校驗過程中,只要找到匹配的許可權之後,就不會再繼續往後查詢是否還有匹配的許可權資訊,而直接完成校驗過程。

四、MySQL訪問授權策略

1、前言

  1. 在我們瞭解了資料庫系統安全的相關因素和mysql許可權系統的工作原理之後,就需要為我們的系統設計一個安全合理的授權策略。
  2. 我想,每個人都清楚,想要授權最簡單最簡便方便,維護工作量最少,那自然是將所有許可權都授予所有的使用者來的最簡單方便了。
  3. 但是,一個使用者所擁有的許可權越大,那麼他給我們的系統所帶來的潛在威脅也就越大。
  4. 所以從安全方面考慮,許可權自然是授予的越小越好。一個有足夠安全意識的管理員在授權的時候,都會只授權必要的許可權,而不會授予任何多餘的許可權。

2、授權策略:

  1. 我們從安全的角度來考慮如何設計一個更為安全合理的授權策略。
  2. 首先需要了解來訪主機:

    (1)由於mysql資料庫登陸驗證使用者的時候是除了使用者名稱和密碼之外,還要驗證來源主機,所以我們還需要了解每個使用者可能從哪些主機發起連線。
    (2)當然,我們也可以通過授權的時候直接通過“%”萬用字元來給所有主機授予都有訪問的許可權,但是這樣就違背了我們安全策略的原則,帶來了潛在風險,所以並不可取。
    (3)尤其是在沒有區域網防火牆保護的情況下,更是不能輕易允許可以從任何主機登陸的使用者存在。
    (4)能通過具體主機名和IP地址指定的儘量通過使用具體的主機名和IP地址來限定來訪主機,不能用具體的主機名和IP地址限定的也需要用盡可能小的通配範圍來限定。

  3. 其次,瞭解使用者需求:

    (1)既然要做到僅授予必要的許可權,那麼我們必須瞭解每個使用者所擔當的角色,也就是說,我們充分了解每個使用者需要連線到資料庫上完成什麼工作。
    (2)瞭解使用者是一個只讀應用的使用者,還是一個讀寫都有的使用者,是一個備份作業的使用者還是一個日常管理的使用者,是隻需要訪問特定的資料庫,還是需要訪問所有的資料庫。
    (3)只有瞭解了需要做什麼,才能準確的瞭解需要授予什麼樣的許可權。
    (4)因為如果許可權過低,會造成工作無法正常完成,而許可權過高,則存在潛在的安全風險。

  4. 再次,要為工作分類:

    (1)為了做到各司其職,我們需要將需要做的工作分門別類,不同類別的工作使用不同的使用者,做好使用者分離。
    (2)雖然這樣可能會帶來管理成本方面的部分工作量增加,但是基於安全方面的考慮,這部分管理工作量的增加是非常值得的。
    (3)而且我們所要做的分離也只是適度的分離。比如將執行備份工作、複製工作、常規應用訪問、只讀應用訪問和日常管理工作分別分理出單獨的特定賬戶來授予各自所需許可權。
    (4)這樣,既可以讓安全風險儘量降低,也可以讓同類同級別的相似許可權合併在一起,不互相交織在一起。
    (5)對於PROCESS、FILE和SUPER這樣的特殊許可權,僅僅只有管理類賬號才需要,不應該授予其他非管理賬號。

  5. 最後,確保只有絕對必要者擁有GRANT OPTION許可權:

    (1)之前在許可權系統介紹的時候我們已經瞭解到GRANT OPTION許可權的特殊性,和擁有該許可權之後的潛在風險,所以在這裡就不贅述了。
    (2)總之,為了安全考慮,擁有GRANT OTPION許可權的使用者越少越好,儘可能只讓擁有超級許可權的使用者才擁有GRANT OPTION許可權。

五、安全設定注意事項

  1. 使用私有區域網。我們可以通過使用私有區域網,通過網路裝置,統一私有區域網的出口,並通過網路防火牆裝置控制出口的安全。
  2. 使用SSL加密通道。如果我們對資料保密要求非常嚴格,可以啟用mysql提供的ssl訪問介面,將傳輸資料進行加密。使網路傳輸的資料即使被截獲,也無法輕易使用。
  3. 訪問授許可權定來訪主機資訊。我們可以在授權的時候,通過指定主機的主機名、域名或IP地址資訊來限定來訪主機的範圍。
  4. OS安全方面。關閉mysql Server主機上面任何不需要的服務,這不僅能從安全方面減少潛在隱患,還能減少主機的部分負擔,儘可能提高效能。
  5. 使用網路掃描工具(如nmap等)掃描主機埠,檢查除了mysql需要監聽的埠3306之外,還有哪些埠是開啟正在監聽的,並去不必要的埠。
  6. 嚴格控制OS賬號的管理,以防賬號資訊外洩,尤其是root和mysql賬號。
  7. 對root和mysql等對mysql的相關檔案有特殊操作許可權的OS賬號登陸後做出比較顯眼的提示,並在Terminal的提示資訊中輸出當前使用者資訊,以防止操作的時候經過多次使用者切換後出現人為誤操作。
  8. 用非root使用者執行mysql。因為如果使用root執行mysql,那麼myslqd的程序就會擁有root使用者所擁有的許可權,任何具有FILE許可權的使用者就可以在mysql中向系統中的任何位置寫入檔案。
  9. 檔案和程序安全。合理設定檔案的許可權屬性,mysql的相關資料和日誌和所在資料夾屬主和所屬組都設定為mysql,且禁用其他所有使用者的讀寫許可權。以防止資料或者日誌檔案被竊取或破壞。
  10. 確保mysql server所在的主機上所必要執行的其他應用或服務足夠安全,避免因為其他應用或者服務存在安全漏洞而被入侵者攻破防線。
  11. 使用者設定。我們必須確保任何可以訪問資料庫的使用者都有一個比較複雜的內容作為密碼,而不是非常簡單或者比較有規律的字元,以防止被使用字典破解程式攻破。
  12. 在 MySQL初始安裝完成之後,系統中可能存在一個不需要任何密碼的root使用者,有些版本安裝完成之後還會存在一個可以通過localhost登入的沒有使用者名稱和密碼的帳號。這些帳號會給系統帶來極大的安全隱患,所以我們必須在正式啟用之前儘早刪除,或者設定一個比較安全的密碼。
  13. 對於密碼資料的存放,也不要存放在簡單的文字檔案之中,而應該使用專業密碼管理軟體來管理(如KeePass)。
  14. 安全引數。不需要使用的功能模組儘量都不要啟用。例如,如果不需要使用使用者自定義函式,就不要在啟動的時候使用“--allow-suspicious-udfs”引數選項,以防止被別有居心的潛在威脅者利用此功能而對MySQL的安全造成威脅;
  15. 不需要從本地檔案中Load資料到資料庫中,就使用“--local-infile=0”禁用掉可以從客戶端機器上Load檔案到資料庫中