回到人間,聊聊數據表誤刪的防止
經過艱苦的跋涉,前天下午終于走出沒有信號、沒有人、沒有污染的阿布吉山區。走到九龍牧場的山脊的時候,遠遠可以看見公路和公路上偶爾駛過的汽車時,心情還是有點小激動的。
本次徒步五天四夜,實際上是5天,第一天下午從洗臉盆埡口出發只走了4公里就宿營了,最后一天13公里的下撤也只走了差不多五小時,總體來說還是比較輕松的一次徒步。走阿布吉措之前,我一直認為這是一條兩星級左右的入門線路,因此本次除了三個大學生和準大學生小朋友外,都是50多歲到60多歲的老朋友。
沒想到走下來,線路難度還是不低的,領隊說線路難度在3星到3星半之間,我覺得這個評價還是準確的,有些事情,不親自去體驗一下,光是紙上談兵,會謬之千里的。十分高興的是在4417米的金柱埡口上居然能夠收到中國移動的信號,正好這個時候收到了兒子被北京化工大學化學與生物工程雙學位專業錄取的短信,還是很高興的。
一出山就收到不少消息,其中有一起數據庫被誤刪數據,導致業務中斷的案例。這是我在7月份看到的第二個誤刪數據影響業務的案例了。誤刪數據現在已經是對系統運行安全較大的威脅了,今天出山后恢復寫公眾號的第一天,我們就來討論討論這個問題吧。
防止誤刪數據這個永恒的話題我是從20多年前就在關注了,1999年的時候一家銀行找到我們,讓我們幫助寫了一個C/S架構的小工具,所有的數據庫維護操作都必須通過這個工具連到數據庫上去做,并且內置了危險SQL的執行確認告警,以及刪除數據操作的審批等流程。工具很簡單,1個POWERBUILDER工程師花了不到一個月就完成了。這個工具一套賣幾十萬,居然也賣出去好幾套。
從防止誤操作的角度去看,可以從制度上去約束,制定嚴格的檢修流程,不過這種制度化的手段往往百密一疏,一次疏漏足以釀成大錯。因此純粹依靠制度是不行的。必須通過一些技術手段來防范。
技術手段分為外部防護和內部防護兩種。外部防護可以通過數據庫防火墻和類似我們二十多年前做的數據庫運維工具等方式來加強管理。對于誤操作能夠自動提醒甚至自動阻斷。對于核心業務數據的查詢和修改操作可以通過雙崗確認甚至上級審批才能執行(很多行業實際上對于重要變更操作都有這個要求,只是通過制度無法確保效果)。
僅僅采用外部防護還不夠完整。因為總會有高權限的DBA能夠繞過一切外部防護,直接到數據庫服務器上用最高權限的賬號去操作數據庫。因此還需要有一些內在防護的手段。20多年前,我們就幫很多客戶利用Oracle系統級觸發器構建了一些數據庫防誤刪表的防護加固系統,實際使用效果還是很好的。
文章的最后,我介紹一下在Oracle上實現數據保護的一個簡單的例子,在支持系統級觸發器的數據庫上,都可以采用類似的方法來實現。二十多年前,我們幫助不少客戶實施過類似的數據庫關鍵數據加固保護,也利用這種小技巧賺了不少錢。
create table base$del_check(
tab_owner vachar2(100),
tab_name varchar2(100),
state number(10)
);
首先定義一張基礎表,用于需要保護的表的信息。這里我們創建了一張base$del_check的表。然后用下面的系統級觸發器來保護。我稍微做了簡化,沒有帶上Owner等信息。
CREATE OR REPLACE TRIGGER del_check
BEFORE DROP or truncate ON DATABASE
declare
vs_tab varchar2(100);
cursor cur_tab is
select LOWER(tab_name) from base$del_check
where stat=1;
BEGIN
open cur_tab;
loop
fetch cur_tab into vs_tab;
if cur_tab%notfound then
exit;
end if;
IF LOWER (ora_dict_obj_name ()) = vs_tab
THEN
raise_application_error (num => -20000,
msg => '你傻啊,這張表都敢刪!!!!');
END IF;
end loop;
close cur_tab;
END;
上述工作做完后,只要是base$del_check中state為1的表,你要去做DROP/TRUNCATE等危險操作的時候,就可以直接被系統禁止了。大家有興趣的話可以繼續優化這個腳本,并用于生產環境。