一、引言
读完了知乎上对于“删库”这个话题下面的讨论,我感受颇深,“删库”这两个字虽然最近已经成为了计算机专业的学生或工作人员开玩笑的常用词汇,但与此同时,这其实也是一个严肃的安全问题。
删库这个操作没有太大的难度,但造成的损失确实巨大的,尤其是对于一些大型公司,他们的数据有很高的含金量,删库这种操作会对他们造成巨大的损失:
“某机场请了一个大牛DBA去帮忙调数据库的时候出了意外,结果几个小时内整个机场无法正常运行,损失几百万”
“所有用户都不能缴费。这可是一千三四百万金额的钱啊,银行已经扣钱了”
...
出现这种事情不仅仅是因为某个人不小心的结果,后面隐藏着整个团队或公司的安全意识淡薄,看了这么多的讨论,我发现意外发生的原因主要集中在”管理”、“备份”、“习惯”这几点上。
二、问题分析
1.管理:
首先来说一下管理的问题,管理在技术上主要体现在权限,常见的问题就是给一些技术不够熟练或者不靠谱的人较高的权限,知乎下面很多人都是由于不小心改动了正式库,才造成了巨大的损失,如果他们只能修改测试库的话就不会造成这么大的问题。体现的更明显的则是在Linux下,很多人都是有了root权限之后执行了”rm -rf /”这条命令,然后才使得悲剧发生,而在讨论中查找“实习”这个关键词之后,却能看到很多的结果,可见正是由于这种权限的管理不严密,才造成了这些意外的发生。
除此之外团队内部的协调问题也会造成严重的安全问题,比如:“初步检查发现是我周末的清理临时文件的计划任务脚本,因为逻辑是“进入XX目录,然后删除所有文件”结果XX目录当时不存在(被另一个同事重命名了)从而在根目录开删”,这段话,这就是一个协调不够好的结果,造成这个结果的可能原因就是命名不够醒目,比较随意,导致同事人为这是一个无关紧要的文件然后重命名或者删除。协调还体现在文档上,很多突发情况发生时,很少看到有人去查看相关的文档,这有两种可能,一种是开发人员没有书写相关的文档,另一种是使用人员没有看文档的意识,不管是哪一种,他们都忽略了文档的重要性。
最后就是团队应该对可能出现的问题做好预案,并且提前给员工打好预防针,真的不小心操作失误一定要及时的报告上级,而不是隐藏:一方面,由于有日志,隐藏不太可能,另一方面,知道操作原因也有助于团队及时进行补救,相比及时进行补救,隐藏等待问题爆发造成的损失更大。
2.备份:
在话题下面的案例中,大多数人的救命稻草都是”备份”,无论大型还是小型公司往往都会有备份,就是备份时间长短的问题,或是几月,或是几天。但是意外发生时,几月前的备份和几天甚至一天前的备份的修复体验可就完全不同了,没备份就只能靠手工,而这效率则极低,所以犯错的人要付多大的代价完全取决于备份的人有多懒了。
个人的经历则往往更惨,很多案例都是不小心格式化了自己的电脑、自己的U盘,然后失去了十几年的青春回忆,甚至里面雷军的例子--被修过电脑时候不再写代码。如果他们曾经备份过,就可以极大的减小自己的损失了。
3.习惯:
个人习惯也往往会造成很大的影响,这里根据文档中的案例列举一些常见的不良习惯:
- 格式化之前不确认有没有重要资料。
- 对生产库与测试库或者生产环境与测试环境没有明显的区分。
- update、delete不加条件或没有审核条件。
- Shift+delete删除文件。
- 没有及时git。
- 执行不熟悉的命令。
- rm -rf前没有任何的确认
三、问题重现与解决方法
这一节根据上一节分析出的一些问题进行重现,并提出解决方案,在可能的情况下对解决方案进行演示:
1.管理:
就从权限问题上来进行重现,展示数据库和Linux系统下给一些技术不够熟练的人一些不恰当权限可能带来的危害。
1.1.数据库操作:
![图1.对一些重要的表给予一名新手过高的权限可能发生的事情](https://i-blog.csdnimg.cn/blog_migrate/771ced9a5260f41a29f1e795b1b886da.png)
![图2.严格把控权限后执行危险语句的结果](https://i-blog.csdnimg.cn/blog_migrate/45bf6282e50bd598f1ed6e5210c6a727.png)
数据库本身已经有权限的机制了,作为DBA应该灵活的运用GRANT与REVOKE语句,给予每个人恰当的权限,而不是一股脑的给每个人所有权限。这也说明一个公司拥有一个负责的DBA的重要性,这样做也可以在根源上断绝新人犯错误的可能性,从图1和图2的对比也可以明显的看出这样做的好处。
1.2.Linux控制台操作:
![图3.某人执行了rm -rf语句造成的后果](https://i-blog.csdnimg.cn/blog_migrate/8bf8b528ebbd7ba1edf0455ca74c925e.png)
Linux控制台下执行rm -rf这条语句往往会造成严重的后果,如图3,很多重要的文件一秒消失。作为系统管理员,就有职责预防这条语句执行时可能造成的后果。
![](https://i-blog.csdnimg.cn/blog_migrate/db9397fbe656fc75bc39d80d15a2f64b.png)
首先对于一些用于读的文件,管理员可以在读写权限上进行控制,如图4,利用chmod命令将文件或文件夹对他人的权限置为只读,这样可以有效的防止他人删除自己的文件,除非他拥有root权限。
![图4.管理员严格限制了权限后执行rm -rf的情况](https://i-blog.csdnimg.cn/blog_migrate/425dcd4e5326cb6e014d6d1f0fdd0d77.png)
管理员也可以使用chattr这个更强大的命令来对文件进行保护,它可以改变文件属性,让删除变得更难。如图5,在使用了chattr命令后,他人首先无法对文件进行删除了,非但如此,自己如果误删文件,也无法成功,甚至使用sudo命令也是如此,这也足以见得该命令对于文件的保护之强大。当然这种保护也不是永久的,随时可以把文件属性再修改为可修改,但这需要sudo权限,如果有人专门取消了文件不可删除属性然后再进行了删除,也基本上可以确定删除操作是故意执行的了。
1.3.管理层面的措施:
由于没有相关的经历,这里我摘取了讨论中一些感觉比较有效的例子作为参考,虽然这可能导致工作效率较低,但是应该足够安全:
“看了这个回答就发现我们公司这么变态的安全管理还是很有必要的。
要删库?对不起,所有碰production database的代码都得先review,再提交,再release才可以。想要误操作一下,至少得过peer reviewer和release engineer两关才操作得了。
即使这样,我好像还是不小心删过一回。不算删吧,写错地方,把其他数据覆盖了。幸好每个小时都有备份,马上恢复,大概损失了5分钟的数据。
故意删文档的遇到过一个。X被从A项目调到B项目去,心怀不满,当即就把A项目的所有文档全删了。接手的发现了,马上汇报上级。第二天,凡经过X手上使用过公司电脑删除过的所有文件都回来了转到了X老板手里面,工作N年累计的几十万个文件,包括很多X很多私人文件,什么自己记的帐,还有保险单之类的,全部都恢复出来了。之后X就被开除了。后来我才知道,公司所有电脑,每15分钟到一个小时都会自动备份。
所以我也绝对不敢在公司电脑上干私事。” --知乎匿名用户
“搞了这么多年数据库还没有犯过这种错误,不是个人水平厉害,而是运营制度严格。太TM严了,我不觉得一般公司有必要搞的大家跟神经病似的,不过还是分享一下吧。还有要是公司没钱,就不用浪费时间继续往下看了
1,首先任何人犯错都不是个人问题,而是制度的问题。不论技术多高,学历多牛,经验多丰富,只要是人,都有可能犯错,区别是犯错的概率有大有小。要防止(完全防止理论上是不可能的)或减少个人犯错的几率,首先从规章制度下手,比如:
分割环境。在线数据库除了支持在线业务,不承担任何其他功能。开发,测试,预演都要有自己的拷贝,各个环境之间物理分割。
权限控制。运营数据库只允许运营部门访问,所以只有可能运营的人不小心在非在线环境犯错,开发和测试人员不会在运营环境犯错。
系统变动。在线数据库不能随便改,哪怕是很小的改动,公认的人畜无害,也不能不经批准擅自改动。这主要是保证在线系统的稳定性,还有就在遇到复杂的bug,可以迅速回到以前的状态。
自动化。这个很重要,没时间展开聊,基本想法是机器出差的概率比人低。
2,系统变更要有严格的管理和详细的记录。这个不是给事后诸葛亮预备的,在改动之前相关人员和部门要清楚更改内容,无论是数据库升级,还是改个密码,大家要清楚为什么改,改什么,改了以后有什么影响,改出问题怎么办。
下面内容太多,懒了。。。
计划
测试
批准
更改
紧急情况
3,在线系统的问题是所以人的问题。负责运营的兄弟们是不是听过类似“这个代码在QA跑的好好的,在你们这儿出的问题和我无关”?这种思想从上到下一定要杜绝,我的问题就是公司的问题,公司的问题就是你的问题。我见过为了赶进度测试不完整,代码不优化,全等到了production再说的部门,操作这种产品出差率很高,甚至有时不得不在线修改。
4,在线系统稳定性由高层决定。
前边说的说到底就是钱的问题,不过有钱有有钱的活法,没钱有没钱的活法,全看大boss是不是舍得给运营部门投钱。想要五个9的数据库,全套测试环境要花钱,全套预演环境要花钱,自动化软件,管理软件也要花钱,什么?没钱?那对不起删库有可能无法避免。” --知乎用户’向往退休’
2.备份:
2.1.数据库备份方式:
由于数据库往往部署于Linux服务器上,因此我们可以利用Linux的脚本来实现自动化部署。
首先实现一个备份用的脚本:
#!/bin/bash
#文件名: backSql.sh
#用途:备份数据库
USERNAME='test' #数据库用户名
PASSWORD='test' #数据库密码
DATABASE='ztest' #数据库名称
curDate=`date "+%Y-%m-%d_%H:%M:%S"` #文件名根据当前时间生成
mysqldump -u$USERNAME -p$PASSWORD "$DATABASE">~/桌面/信息安全/test/$curDate.sql
然后在crontab里面添加一个新的任务:
![图6.添加备份任务到计划任务表中](https://i-blog.csdnimg.cn/blog_migrate/23b552e1341c2b8f6289c4e35f31c804.png)
这里为了演示,设置两分钟备份一次,实际上一小时备份一次就已经足够了。
![图7.运行情况](https://i-blog.csdnimg.cn/blog_migrate/2a4062a3262e52863da830986a5ef7e4.png)
2.2.Linux部分文件备份方式
对于Linux下的一些重要的源代码或者图片之类的文件也可以经常进行备份,或者写到crontab中进行定时备份,我们可以利用简单的zip之类的压缩命令压缩目标文件夹,然后配合ssh命令上传到某其它服务器中实现备份的目的,也可以利用rsync命令更方便的实现快照功能。
之前学Shell脚本的时候用zip和except命令实现过一些脚本来对一个文件夹进行过备份:
![图8.back.sh备份的主要逻辑](https://i-blog.csdnimg.cn/blog_migrate/6dfeccc926a8985a5fad5a55e7ebf9ac.png)
![图9.upload.sh 上传压缩过的文件](https://i-blog.csdnimg.cn/blog_migrate/2b1aa4c6f7c0ebdbaea7982bd54e1873.png)
![图10.deleteHistory.sh 删除历史文件](https://i-blog.csdnimg.cn/blog_migrate/57ebef8e0493fb229ea93cb7e958fa29.png)
基本思路就是在本地对文件夹进行压缩,然后上传到云服务器,并且清除掉历史文件,不过事实上,Linux下也有更好用的自带的备份方式,就是rsync命令:
![](https://i-blog.csdnimg.cn/blog_migrate/317e70e897a008f951adbc4e4064fa19.png)
如图11所示,使用rsync命令可以一键将文件备份到远程服务器,在需要的时候可以再将其很轻松的恢复到本地,而不需要编写额外的脚本。这个命令也可以配合crontab使用,使得备份更加自动化。
2.3.关于备份的其它要注意的点:
执行自动化备份之后应该经常抽查备份文件,查看备份是否与预期的相同,有时候有可能由于某种原因导致备份文件出错,而这相当于毁掉了自己的救命稻草,因此应该经常检查确保万无一失。
此外有时候没有很好的备份时我们可以查看运行日志,比如MySQL数据库就可以查看binlog,这样即使通过手工输入也能挽回部分损失,知乎下的讨论中很多没有做备份的人也是用log保住了一部分数据。
3.个人习惯:
个人不良习惯也是导致危险操作的原因之一,这里我从讨论中找出了一些很好的做法或者是自己想出的一些应对方式。
3.1.生产库与测试库 生产环境和测试环境分不清:
生产环境和测试环境的控制台最好使用不同的用户名登录,同时主机名也尽量避免重复,这样可以帮助我们分清测试环境和生产环境。
此外知乎下有人提供的在mysql下分清两种环境的建议也非常不错:
“启动mysql时设定一个特定的prompt。使用--prompt=来给生产环境设置一个特别的提示符。
$ mysql -uroot -p --prompt='PRODUCTION> 'PRODUCTION> SELECT 1 + 2;”
3.2.在根目录下rm -rf或者是在root权限下cd ..进入根目录:
关于这点我觉得最好的方法是尽量不要用root角色来做事,需要高权限的时候再sudo比较好,此外rm -rf之类的危险操作之前最好先使用pwd来查看一下当前目录,确保自己不会做出什么不好的事情来。
3.3.直接运行不知道的命令:
这是一个很危险的做法,在多人工作的情况下,谁用了某个命令就要对自己的行为负责,所以最好不要去贸然执行不知道的命令,否则就要背这个锅。在自己工作的时候即使要执行不知道的命令,也最好百度一下用法,防止造成不必要的损失。
3.4.update、delete不加条件或条件加错:
我在执行update和delete之前,会先用select语句加上where执行一下看看会有多少结果收到影响,然后再使用delete或者update语句正式执行,这样做会让自己在修改数据之前再次确认,防止自己出错。
![图12.MySQL Workbench执行危险语句时的效果](https://i-blog.csdnimg.cn/blog_migrate/3289992d1af3e4a3097455c0dba1661a.png)
此外,在MySQL Workbench中尝试执行不加where的语句时,它会报错,如图12,而直接在命令行中执行却不会,这也说明了一些数据库可视化工具已经考虑到这种粗心的问题了,所以我们也可以利用这些工具来辅助我们对数据库进行操作。
3.5.删除非常彻底,不留后路:
知乎话题下的讨论中,我看到了很多不错的做法,比如:
- 删除时不要用shift
- 不要着急清理回收站,除非确认这些东西不会再用到
- 尽量用mv命令而不是rm命令来删除
总之原则就是“给自己留条后路”,所以我现在在删除某个文件时也往往使用mv *** ***.old来代替rm ***,希望有一天也会感谢自己的这种做法吧。
3.6.不会善用git:
很多团队或者都会使用git来进行代码的维护,但如果写了代码不commit、push,一旦发生了什么意外,可能很多天的工作量都变成了徒劳。因此经常commit并且写好详细的注释才是最好的做法,一方面,这样可以让别人看见自己的努力,另一方面,这也是对自己的一份保险,即使本地的代码库没了也可以再pull一份下来而不是从头再来。
四、总结:
总之,“删库”这个问题发生的原因主要在于人们的安全意识不够,我们可以用管理+技术来对这种情况加以预防,同时也要培养自己良好的习惯,防止不好的习惯给自己带来不良的影响,最后希望“从删库到跑路”这句话只存在与玩笑之中吧。