发布信息

五一节前的悲剧:我在公司服务器上写了个巨蠢的 Bug,删库了

作者:软荐小编      2024-09-13 10:07:51     78

前几天,临近五一劳动节假期,一想到五天长假,我就有点得意忘形了。于是就没注意写一个简单的 Bash 脚本,写完也没检查,就直接拖到物理服务器上跑了。

软件文档编制_文件编辑软件下载_rm文件编辑软件

图片来自 Pexels

结果开始运行就出错了,这么简单的脚本怎么可能跑了10秒还跑不完呢?于是我立刻按下Ctrl+C,停止了正在运行的脚本。

文件编辑软件下载_rm文件编辑软件_软件文档编制

然后,我习惯性地输入了 ls。发生了什么?找不到 ls 命令?

文件编辑软件下载_rm文件编辑软件_软件文档编制

我感觉后背一凉,慌乱地打开脚本,发现问题了,我写了一个愚蠢的bug,间接执行了rm -fr /*,这不就是把库删了吗?

rm文件编辑软件_文件编辑软件下载_软件文档编制

这是公司的授权服务器,如果我把它弄乱了,公司的历史授权记录等重要信息不是会丢失吗?

我很慌张,就把这件事告诉了我的朋友,朋友建议我尽快向领导汇报,不要把删除数据库的事瞒着。

于是我向领导汇报了删除数据库的想法,但我以为我会受到严厉的批评。

Leader笑道:“没事,你看看那些重要文件还在不在,不过顺便说一句,我突然想起来,我有半年没备份过我的编译服务器了,我先备份一下我的编译服务器,免得哪天被你删了。”

正在看节目的朋友们,你们以为我会删掉数据库然后跑掉吗?哈哈哈,我没跑掉,而是恢复了。那么接下来我就讲讲我是怎么删掉数据库然后恢复的。

犯罪现场的初步调查

我们先来看看我写的垃圾代码是如何导致库被删除的:

软件文档编制_rm文件编辑软件_文件编辑软件下载

由于出现了rm -fr /*现象,所以new_lic_dir变量肯定是空的。

所以当执行 rm -fr $new_lic_dir/* 语句时,就变成了 rm -fr /* 语句来删除库。太好了,凶器找到了。

那么为什么new_lic_dir是空的呢?细心的朋友肯定注意到了,这是因为在给new_lic_dir变量赋值的时候使用了反引号。

是的,是因为反引号。反引号在 Linux Shell 命令行中有一个特殊含义:反引号之间的内容会被 Shell 优先执行,将其输出放入主命令中后,主命令才会被执行。

换句话说,new_lic_dir 的值是执行命令 ${lic_path}/new_license 的结果。问题是这不是一个命令,所以它必须向 new_lic_dir 变量返回一个空值。

我写的温柔的代码原来是恶意的删库代码。

文件编辑软件下载_rm文件编辑软件_软件文档编制

现在找到原因了,反引号要改成双引号。(内心OS:你真是菜鸟,这么简单的赋值命令都写错了!)

哈哈哈,我真的很烂,前面也说了,快五一了,迷迷糊糊的写了这段代码,于是习惯性地开启了程序员第一武功:Crtl+C、Crtl+V。

我把第一条赋值lic_path=`pwd`的语句复制粘贴过来,然后只改了变量名,没注意到反引号要改成双引号,导致删除库的悲剧。

保护犯罪现场

由于数据库已被删除,请不要重新启动服务器或关闭 SSH 连接会话。相反,请保留犯罪现场,然后检查剩下的东西。

PS:这不是吹牛吗?ls 没了怎么查看?

幸好,这次我运气比较好,因为在执行脚本的时候,我第一时间发现了错误,并立即终止了还在运行的脚本,所以并不是所有的Linux文件都被删除了。

只要我动作快,rm -fr /* 不会害死我。虽然 ls 被删除了,但我幸运地发现 cd 命令仍然有效。

只要你用好 cd,它也可以用来达到和 ls 一样的效果。很简单,只要按 cd + Tab 键,就会自动出现指定目录下的所有文件。

文件编辑软件下载_rm文件编辑软件_软件文档编制

通过cd+Tab键,我们可以查看到各个目录下的文件,这样就可以一步步确认哪些系统文件被删除了。

经过一番确认和对比,发现主要被删除的四个目录分别是:

我们来回顾一下上面四个目录主要存放什么:

/boot被删除了,幸亏小林没有重启服务器,要是重启了服务器,那就灾难了,系统肯定开不了机。

cd命令是在/sin目录下,而/sin依然完好,所以cd可以正常使用。

幸好重要的数据库信息和文件没有被删除,所以小林的第一个目标就是恢复/bin、/boot、/dev、/lib这四个目录。

还原文件

由于/bin目录和/lib下的一些动态文件被删除,导致常用的文件传输方式如ftp、scp、mount等都无法使用。

找了好久rm文件编辑软件,发现可以用wget,wget命令在/usr/bin目录下,幸好/usr/bin还完好。

于是,我用了一个刁钻的办法,先用另外一个普通的服务器,把/bin目录放到Web服务器的Web目录中,然后通过wget下载。

有希望,就有成功的曙光。

但是新的问题出现了,我下载的命令文件没有执行权限。

chmod命令在/bin目录下,该目录也已被删除,无法用来授予文件权限。

不过,我还是在网上搜索了一下,找到了一个很棒的 perl 命令,可以用来授予文件权限:

perl -e "chmod 777, 'ls'" 

好神奇的命令啊,好了,现在权限分配问题已经解决了,成功在望。

wget不能直接下载/bin目录,它只能下载一个文件。

但我无法逐一下载并恢复它们,这将需要数年时间才能完成......

于是我想到了一个方法:

/bin 就这样恢复了,其余目录也通过同样的操作恢复了。

我的笑容渐渐又回来了,哈哈哈哈哈哈哈哈哈哈哈哈!

rm文件编辑软件_文件编辑软件下载_软件文档编制

当遇到rm -fr /*数据库删除事件时,一定要保持冷静,保持心态稳定!

我们之所以能够从这次数据库删除事件中恢复,关键有两点:

以上两点如果做不好的话,服务器恢复的难度就会增加很多,更严重的是五一假期就过不了了。

文件编辑软件下载_rm文件编辑软件_软件文档编制

防止意外执行 rm -fr /*

rm -fr /* 既然是暴力武器,那就必须防范,下面我就给大家讲几种防范的方法。

解决方案1:rm -rf 删除时确定目录

#!/bin/bash  work_path=`pwd`  #如果目录不为空,才执行删除操作 if [ ${work_path} != "" ];then     rm -fr ${work_path}/* fi 

执行目录删除操作之前,先判断需要删除的目录是否为空,如果不为空,则执行删除操作。

解决方案2:Shell脚本指定set -u

执行脚本时,如果遇到不存在的变量,Bash 默认会忽略它。

#!/bin/bash  echo $a echo hello 

上述代码中$a为不存在的变量,执行结果如下。

nbsp;bash test.sh  hello 

可以发现,echo $a 输出了一个空行,Bash 忽略了不存在的$a,然后继续执行echo hello。

当变量不存在时,脚本最好报告错误,而不是默默执行。

set -u 用于改变这个行为,如果把它添加到脚本中,当遇到不存在的变量时就会报错并停止执行。

#!/bin/bash set -u  rm -fr $a/* echo hello 

结果如下:

nbsp;bash test.sh test.sh: line 4: a: unbound variable 

可以看到,由于a是未定义的变量,所以脚本报错,不再执行后面的语句。

解决方案 3:用 safe-rm 替换 rm

safe-rm 是一款开源软件工具,名字听起来很安全,所以用来替代安全性较差的 rm。

可以在 /etc/safe-rm.conf 中配置路径黑名单,定义哪些路径不能被 safe-rm 删除。

我们可以将safe-rm改名为rm,假设/etc/无法删除,那么删除/etc的时候会报错:

nbsp;rm -rf /etc/ safe-rm: skipping /etc/ 

解决方案4:建立回收箱机制

Windows 有回收站,所以即使你误删了一些东西,也可以在回收站里恢复。所以,我们也可以在 Linux 中实现回收站机制。

实现思路:

① 创建回收站目录

mkdir /home/.trash 

② 编写remove.sh脚本,内容如下:

③ 修改~/.bashrc,将其中的rm命令替换为我们自建的remove.sh:

alias rm="sh /home/remove.sh" 

④ 设置crontab定时清空垃圾,如每天0点清空垃圾:

0 0 * * * rm -rf /home/.trash/* 

⑤ 最后执行以下命令使之生效:

source ~/.bashrc  

解决方案 5:将根文件挂载为只读

在 /etc/fstab 文件中,将 / 文件系统挂载为只读。

软件文档编制_rm文件编辑软件_文件编辑软件下载

remount,ro 表示以只读模式挂载。

文件以只读方式挂载后,删除操作无法成功:

文件编辑软件下载_软件文档编制_rm文件编辑软件

反射

对于涉及rm -fr命令的代码,一定要小心谨慎,反复检查,防止误执行rm -fr /*。在测试机上验证无误后,再在真机上运行,​​千万不要大意。

即使发生 rm -fr /*rm文件编辑软件,也立即停止并执行三件事:

只要我们立即终止 rm -fr /*,它就不会杀死我们,我们可以在当前环境中使用剩余的命令,冷静分析,还有机会恢复。

软件文档编制_文件编辑软件下载_rm文件编辑软件

现在的我是一个删库不逃的人了,再见,下次见。

相关内容 查看全部