加入RUN!PC粉絲團
最近新增的精選文章
 
最多人點閱的精選文章
 
 
精選文章 - 開發技術
分享到Plurk
分享到FaceBook
 
Oracle資料庫優化實務經驗談(2) ─常見的資料庫安全漏洞與防範
文/賞金獵人 2010/9/3 下午 04:20:02

當你依正常流程完成用戶對Oracle資料庫存取設定後,你認為你的資料庫就安全?是的,對一般的用戶而言你的資料庫是安全的,但對於Hacker而言仍是不堪一擊的:
●當你利用「SQL*Plus」從Oracle Database讀取資料時,一個稍有功力的Hacker可以輕易的就從網路封包探嗅到你的對話內容,並收集到想要的資訊。
●因為程式開發人員開發經驗不足,Hacker可能只要利用單純的SQL Injection,就可以突破最基本的登入限制,並在你的查詢畫面中強加Delete指令惡意刪除資料。
●預設情況下,互聯網的任何一個用戶都能嘗試連接你的資料庫,並且不受密碼失敗的限制,如果Hacker利用字典暴力破解,那可能會是一場災難!

接下來,將從Oracle Database Server端、網路封包、資料整合性、TableSpace加密,以及開發人員等角度,探討如何進行較好的Oracle Database安全管控。


誰可以連接Oracle Database?
正常情況下,Oracle Database應該只有AP Server,以及程式開發人員才會進行連接。但預設的Oracle Database組態,卻允許任何IP進行連線,這就給了內部惡意人士潛在機會,利用暴力破解法進行特定帳號密碼偵測。

要解決這個問題,你可以利用Oracle Net Manager以正向列表的方式,如圖1,設定哪些IP可以進行連接(設定完之後,需要利用lsnrctl先stop,再start設定才會生效)。


▲圖1 利用Oracle Net Manager設定哪些Client端可以連線。

除了這個方法之外,Oracle Database有一個「PRODUCT_USER_PROFILE」的檔案,可以用來規範哪些Oracle Database的產品(如SQL*Plus),可以被哪些人用來執行哪些命令,例如,你執行了以下命令之後,JACKSON就無法進行任何與Create有關的動作(圖2):






▲圖2 限定Jackson不能Create任何Object。

PRODUCT_USER_PROFILE對於Windows Client端開發人員有用嗎?其實並沒用!在Windows環境,有太多的工具可以連接到Oracle Database(最簡單的末過於透過ODBC + Net Service),SQL*Plus基本已不太有人使用。PRODUCT_USER_PROFILE多用於Linux環境(多半只有SQL*Plus可供連接Oracle Database),例如你的AP Server為Linux,就可以利用以下指令方式,限定一般用戶與開發人員(如Jackson),登入Linux時無法使用SQL*Plus,只有特定發人員可以使用:




用戶連線異常控制
Hacker試圖連線Oracle Database的最大特徵為:不斷的在同一IP、用相同帳號、試不同的密碼,直到登入為止。依照這個入侵特徵可以設定Profile來進行防止。

Profile規範用戶對Oracle Database資源的使用狀況,以及密碼控制原則。對於大型、上千用戶的Oracle database應用過程,你可以經由Profile控制每個用戶可用的資源額度,避免因為少數幾個人的額外資源需求,而影響大部份人的使用效率;同時也可以經由Profile來對每一個用戶的帳號、密碼,進行最基本的內控要求(如限定密碼使用有效日期、密碼複雜度)。

每一個用戶都會被指定一個對應的Profile(沒有指定的會使用預設的Profile),Profile中至少有以下部份與安全管控或連線有關,可以用來規範異常的連線行為:
●Session_per_user:每個User同時可以開啟的Session數。
●Connect_time:Session可連線的總時間,以分鐘為單位。
●Idle_time:允許Session不活動的時間,以分鐘為單位,超過該時間Session將斷開。但是長時間運行查詢和其他操作的不受此限制。
●Failed_login_attempts:User被鎖定之前,允許嘗試登入的次數(如果設為3,則代表可以登入3次失敗,第4次失敗時會鎖定)。
●Password_lock_time:嘗試登入失敗次數到達後,帳戶的鎖定時間,以天為單位。
●Password_life_time:同一密碼所允許使用的最大天數。如果同時指定了password_grace_time參數,如果在grace period內沒有改變密碼,則密碼會失效,連接資料庫被拒絕。如果沒有設置password_grace_time參數,預設值unlimited將引發一個資料庫警告,但是允許用戶繼續連接。
●Password_grace_time:寬限天數,Oracle Database發出警告到登入失效前的天數。如果資料庫密碼在這中間沒有被修改,則過期會失效。
●Password_verify_function:該欄位允許將複雜的PL/SQL密碼驗證腳本做為驗證用戶密碼複雜性的依據。Oracle Database提供了一個默認的腳本,但也可以創建自己的驗證規則或使用第三方軟體驗證。

要運用Profile來控制惡意連線,需依以下步驟進行設定:
●啟用Profile功能,參數resource_limit設為True。
●設定多個Profile,將DBA的帳號與一般用戶帳號所對應的帳號進行區分。
●針對不同的Profile設定不同的參數值,例如給SYS的Profile需針對Password_verify_function設定較高的密碼複雜度驗證。
●針對一般用戶所使用的Profile(一般多為Default),則主要針對Session_per_user、Failed_login_attempts、Password_lock_time進行調整。

筆者用以下的SQL修改Profile的設定為:密碼每60天改一次、每個User最多有3個Session、登入密碼最多可以錯3次、超過3次會鎖定1天:



設定完之後,筆者使用jack帳號先開啟3個Oracle Database連線,再開啟第4個連線時即不能通過,如圖3;其次筆者故意用jack的帳號登入失敗3次,到第4次嘗試登入時,Oracle Database即會鎖定該帳號,如圖4。


▲圖3 利用Profile限定每一個用戶的連線次數。


▲圖4 利用Profile限定每一個用戶登入失敗3次帳號即鎖定。


連線稽核與記錄
大部份ERP都有兩個功能:查核誰連線使用ERP、使用哪些指令。經由這2個功能,可在日後發現ERP資料異常(如薪資資料被竄改、庫存資料被歸0)時留下一些追蹤的蛛絲馬跡。Oracle Database實際上也有類似的功能可以協助ERP進行內控,而且只要用Trigger就能實現。可以利用Trigger掌握:
●特定Table的DML指令,如Insert、Update、Delete。
●特定的Object、Schema、或Database進行特定的DDL指令,如Alter、Create、Drop。
●特定的Database事件,如Startup(之後)、Shutdown(之前)、Server Error(之後)、Log on(之後)、Log off(之前)。

就用戶連線部份,我們可以經由Database事件來進行許多不同的稽核與控制(但使用這類的事件控制前,必需先將_system_trig_enabled參數設為True)。例如可以用以下的方法,建立一個用戶登入、登出作業記錄表。首先在SYS中建立一個連線記錄Table:



接下來建立以下2個Trigger,即可以讓用戶在登入時被記錄,登出時也會被記錄:



以上Trigger建立完立即生效,當用戶登入登出時,即可以查詢logon_off_table得到如圖5的用戶登入與登出狀態。


▲圖5 利用Trigger進行用戶登入與登出記錄。

上述的例子,可以讓DBA明確了解有哪些人登入系統進行操作。至於要抓有哪些人試圖登入、但登入失敗,則可以利用以下的Trigger,在SYS先建立一個存放Login failure的Table,然後再寫一段Trigger來攔截有關於登入錯誤:



我們可以利用Oracle Net Manager,控制哪些開發人員的IP可以連到Oracle Database,那麼是否能進一步控制:特定的人只能由特定的IP或網段登入(如Mary可以在MIS的網段登入、但不能在另一個網段登入)?或是只有上班時間才可以連線?

你可以建立以下的Trigger進一步控制用戶連線(圖6):




▲圖6 針對可以連線到Oracle Database的帳號,進一步控制可連線IP,以及連線時間。

有關於連線與追蹤還有一點需注意的是:資料庫層級的Trigger控制方式對於具有DBA權限的用戶沒有效力。


用戶連線後用戶權限控制
對用戶連線後的權限控制有幾個重點,主要包含幾個部份:
●切勿將DBA Role給予一般存取者。
●不要輕易將Create ANY、Drop ANY、Alter ANY權限給予一般存取者。
●在授與權限時,不要將With grant option同時給予一般存取者。
●不整個Schema授權最好;只做特定Table授權更好;最好的管控則是Column的存取控制。


加密你的網路封包、加強資料完整性
隨著企業電腦應用越來越深,以及B2B、B2P、P2P等各種不同商業模式的出現,電腦資訊流不光在公司內流動,同時也開始在互連網上被某個你所無法掌控的人所運用,在這種分散、甚至對外開放的環境中,安全的網路連線至為重要。為了要充份掌握「誰在使用你的系統?」、「使用者被允許操作什麼?」Oracle DBA必需找到好的方法:
●驗證使用者身份。
●確定只有合法身份的人可以取得合法、未被竄改過的資訊。
●確定只有合法的人可以查看資訊。

但這談何容易?當你從家裡經由ADSL、到公司Firewall、經公司內部交換機、輸入正確的帳號與密碼連到Oracle database時,你能確定都是安全的、沒有人可以從中探嗅到你與Oracle Database溝通中的敏感資訊?你能確定你與Oracle Database溝通程資料內容,沒有被某位網路上惡意人士偷偷修改?Oracle Database被要求讓Mary帳號連線時,連線者真的是Mary?

另一個怪現象是由於電腦應用越多、每個人要記得的帳號與密碼也越多,又造成了以下幾個現象:
●設定簡單、好記、有意義的密碼,但這種密碼很容易就可以用字典暴力破解。
●設定很複雜的密碼,但記錄於特定的地方,被記錄下來的密碼,一不小心流出去就會出事。
●所有系統、Mail的帳號與密碼都一樣,這種方式一旦密碼被破,就會造成大範圍資安問題。

圖7是利用簡易的封包監控工具,在沒有Oracle Database帳號、只是單純網路監聽,就可以輕而易舉的偷窺到用戶與Oracle Database之間的對話內容,這是由於預設的Oracle Database與Client端的連線為「裸封包」。未加密的Oracle database網路封包可能招引2種風險:
●被非法人員查看到Oracle Database敏感資料內容,破壞資料安全性。
●被惡意人員修改封包後,再傳送給Server端或Client端,破壞資料完整性與一致性。


▲圖7 利用網管工具監看Oracle client與Server端的Session內容。

針對前述所提的資料加密、資料一致與整合性、認證等3個問題,可以經由Oracle Advanced Security進行補強。啟用Oracle Advanced Security後,經由加密演算法(RC4 Encryption、DES Encryption、Triple-DES Encryption、Advanced Encryption Standard)加密的資料,仍可在網路上被探嗅,但所查看到的只是一團亂碼,只有持有相應Key的人才能解開。(圖8)


▲圖8 Oracle Client與Server封包傳送過程進行加密。

至於如何確保傳送中的Oracle Database封包不被修改、刪除、造假回應,Oracle Advanced Security提供以MD5或SHA-1 hashing演算法為基礎,針對每一個封包在傳送前進行計算並取得一個計算值,當接收方取得封包後,進行計算並比對是否正確,以了解封包是否被動過手腳。

整個Oracle Advanced Security是與Oracle Net溝通介面整合(所以如果不是走Oracle Net與Oracle Database 進行溝通,將無法使用此功能),因此在Client端與Server端都不會感受到其存在,只需再Server端完成設定即可以使用。(圖9)


▲圖9 Oracle Net與Oracle Advanced Security整合機制。

如果要實作網路封包加密,可以在Server端進入Oracle Net Manager,於圖10中進行設定:加密選「Server」,加密類型選擇「必要」,加密原始內建值為以用產生加密金鑰,必需手動輸入,可用的方法為用以加密的演算方法。

完成設定之後再用網路封包監控工具查看,則會發現封包內容已經變為亂碼。如果要實作資料整合性,則比照圖11的方式進行設定即可以完成。


▲圖10 進行Oracle Database資料封包加密。


▲圖11 設定Oracle Database封包資料整合性。

有關於Oracle Advanced Security設定部份,至少在Oracle 11g中,如果沒有進行資料加密或整合性設定,則不管是在Client端或Server端,預設值都將設為Accept。也就是說當Server端要求時,Client端會預設接受加密或整合性的要求(這也是筆者所說:只需在Server端設定、不需在Client端設定的原因)。有關於Client端與Server端設定對照如表1。




加密 TableSpace與Table Column
所有Oracle Database資料最終仍得存放到實體檔案。但前面談了那麼多似乎都是從邏輯著手安全管控,那麼實體檔案是否也可以被窺視內容?當然可以!針對實體檔案加密的問題,Oracle提供以下解決方案:

●你可以選擇針對敏感資料的欄位進行加密,例如身份證號碼、信用卡號、以及醫療記錄。欄位加密對於有合法權限的程式而言,除了有一點限制外(讀取之前,Server端的Wallet必需開啟),基本上是透明的、沒有影響的。欄位加密,必需使用Oracle wallet來儲存Master encryption key。同時,在你建立加密欄位之前、在你儲存、取得加密資料之前,Oracle wallet也必需是Open。
●如果你計畫針對某一個Table的許多欄位加密、或是,你打算加密許多Table,那麼,針對所對應的Tablespace進行加密或許更好!而Tablespace的加密,對應用程式與用戶而言,一樣也是透明、毫不受影響的(因為那是對存在實體中的資料加密、讀取過程再反過來解密),且效率上會比加密許多欄位來得好。

有關於敏感性資料的欄位加密過程,Oracle之所以發展出這樣的技術,主要因為Oracle Database早期安全管控重點都是在於邏輯、程式的控制,但對於存放在作業系統的實體檔案,則是乾淨、未加密過的資料。

經由新的加密技術,儲存在Data file的資料也是加過密的!並將加密的Key放在與實體檔案分開的外部模組之中(存放地點你決定)!還有一個重點是:對於程式、與用戶而言,此種加密方式毫不產生影響、就像是透明的一樣(Transparent data encryption,又稱為TDE)。

不過由於加密與解密都是在SQL Layer,基本上這種Data encryption是針對數字類型或是敏感資料,但以不在相關的Primary key、Foreign key、Constraint、Check之中的資料為佳(否則資料讀取速度會變慢)。

Transparent data encryption是一個以一個Master encryption key為存取基礎的系統。即便資料已從實體資料庫中讀出來,在你未經過合法的解密之前(這個動作對合法存取的用戶而言,是自動會進行的),資料仍然是無法被了解的!

當Table中某一個欄位(或多個欄位)被加密後,會有一個Single key被配置給這個Table,這個Key稱為Column encryption key,並被Database server的Master encryption key加密,並被保存於Dictionary table。

如同圖12,Master encryption key是儲存於外部的安全管控模組、與資料庫完全無關、且只有Security administrator可以存取,這個外部的安全管控模組Oracle使用的是Oracle wallet。


▲圖12 Transparent data encryption。

將外部安全管控模組與現有的Database server分開是有道理的,如此Database administrator與Security administrator可以是不同人,彼此可互不知道密碼。例如存取非敏感資料時(如人事、考勤資料),在沒有將這個Key給Open起來之前,仍可以正常運作、可以讀取非敏感資料,但對於敏感資料,就算是你DBA,但你沒有Master key,你也一樣看不到,例如薪資系統的薪資項目,就算你是DBA,對於被加密的欄位一樣看不到!除非這些加密的欄位經由Key解密。

如果要實作Transparent data encryption,首先設定Wallet所要存放的位置。Wallet的存放位置是由sqlnet.ora中的參數「ENCRYPTION_WALLET_LOCATION」所決定,筆者設定資料如圖13。


▲圖13 設定Wallet存放位置。

接下來依以下步驟進行:
●執行SQL*Plus,並以sysdba登入。執行命令如:「ALTER SYSTEM SET ENCRYPTION KEY IDENTIFIED BY “your_password”」,就可以在sqlnet.ora所指定的wallet location中建立Wallet。
●你可以下指令來Open、Close,以及查看Encryption wallet。需注意,當Oracle database instance shutdown時,Wallet會跟著Close,但Instance startup時,Wallet並不會自動Open,而是必須下指令。Open wallet:「ALTER SYSTEM SET ENCRYPTION WALLET OPEN IDENTIFIED BY “PASSWORD”」;Close wallet:「ALTER SYSTEM SET ENCRYPTION WALLET CLOSE」;查看Wallet資訊:「Select * from V$encryption_wallet」。但如果你的Oracle Database所在的環境為Windows Server,則可以利用Oracle Wallet Manager,並設定為「自動登入」來自動開啟。(圖14)


▲圖14 開啟、關閉及查看Wallet狀況的不同SQL指令。

此時我們已經完成了Wallet的設定,接下來筆者來測試建立具有部份欄位加密的Table,如圖15(有兩點需注意:第一必須在Wallet Open的情況下,才能使用Transparent encryption data的功能,所以你得先以SYSDBA身份打開Wallet;第二則是,如果你以SYS身份登入,則其所對應的Schema object則不能使用本功能,所以你必需切換為別的用戶)。


▲圖15 建立具體部份加密欄位的Table。

建立好abc表格後,以ken登入並輸入兩筆資料,然後再切回SYSDBA並關閉Wallet,則要查詢abc表格所有欄位資料時便會出錯(這驗證了加密的資料必需在Wallet打開時才能讀取),但只查詢未加密的id欄位則無此問題(未加密的資料不受Wallet影響)。(圖16)


▲圖16 關閉Wallet時有加密的欄位無法查詢。

為了要了解實體檔案是否也加過密,筆者利用圖17指令將資料Dump出來,於圖18中進行分析發現:
●筆者可以找到「Q123」,也可以找到「Q456」,但就是找不到「BOY」。
●在筆者針對Q123的資料細部分析,發現「Q123」在實體檔案中佔用4 byte,存檔的相對應16進位分別為&H51、&H34、&H32、&H33,如果你用VB的Chr指令去轉換,可以得到的就是Q123,但「BOY」的值則被拆成了52 Byte!處於加密狀態,筆者無法破解。


▲圖17 Dump Oracle實體資料檔案。


▲圖18 加密過的欄位,Dump出來之後一樣為加密。


別讓開發人員變成Hacker的打手!
大部份的開發人員撰寫程式時多半有以下習慣:
●先寫SQL主體,然後將用戶輸入的條件逐一的串在一起,例如:「Select * from abc where id=’”+ txt_id.text+”’”」。
●直接將SQL送到資料庫處理函數進行處理。
●處理過程認定只會返回一個結果集。

這真可說是個壞習慣。因為就上面例子而言,正常情況下txt_id.text所要輸入的應該是ID代號,但Hacker可不是這樣輸入的!他們可能會輸入令你意想不到的字串,讓SQL變成:「Select * from abc where id=’1’ or ‘1’=’1’」,就可以抓到所有的資料。

如果Hacker存心找麻煩,讓SQL變成:「Select * from abc where id=’1’ or ‘1’=’1’; delete * from abc;」,且你用的是C#配合ADO.NET,那麼你可能會有大麻煩!如果不小心這些SQL Injection的問題,那麼你所開發的合法系統,恰好成為Hacker最好的入侵工具。


結語
本文分別從邏輯、實體,以及資訊傳遞信號等三大角度,說明Oracle Database安全管控精神,此三者只要能適度進行把關,那麼「家賊」、「外賊」也就不容易入侵了。

【原文刊載於RUN!PC雜誌:2010年8月號】