您现在的位置是:网站首页>技术百科技术百科
编写安全的Shell脚本
小大寒2024-01-01[技术百科]博学多闻
编写安全的Shell脚本本篇文章讨论了编写安全Shell脚本的基本原则。它提醒我们,尽管Linux比Windows更不容易受到恶意攻击,但任何设备都可能遭遇风险,尤其是互联网连接的设备。文章通过实际例子展示了常见的安全漏洞,如特洛伊木马攻击、存储密码和未处理的用户输入,强调了在脚本中避免使用不安全的做法,如使用绝对路径调用命令、避免存储密码、清理用户输入等。此外,建议使用已编译的程序代替Shell脚本来避免潜在风险,特别是对于CGI脚本。《原文》
编写安全的Shell脚本
不要用草率的脚本暴露你的系统!
虽然Linux桌面或服务器相比典型的Windows设备更不容易受到病毒和恶意软件的侵害,但没有任何连接到互联网的设备能完全避免攻击。攻击者可能是典型的书呆子,躲在卧室里测试自己的黑客技能(想想电影《战争游戏》中的Matthew Broderick或者《黑客帝国》中的Angelina Jolie)。当然,也可能是某些有组织的军队、犯罪团伙、恐怖组织或其他资金支持的实体,通过十几个重定向的攻击向量创建大规模的僵尸网络,或者窃取数百万张信用卡信息。
无论如何,当今的系统面临的威胁在UNIX早期开发时期甚至Linux作为UNIX的业余重实现的最初几年是难以想象的。啊,回到过去,最大的担忧是版权问题,因此为了摆脱AT&T贝尔实验室的许可等,实用工具经常被重新从头实现。
我对此也有一些个人经历。我为BSD 4.2重新编写了游戏Hunt the Wumpus(猎捕巨兽),wumpus
,当时伯克利团队正在努力摆脱AT&T UNIX的法律困扰。我知道,这并不是一个值得骄傲的成就,但我也在那个时期设法拼凑了一些其他的实用工具。
然而,互联网的发展却是反向的。在现实生活中,无法无天的西部逐渐被驯服,守法的公民取代了19世纪50年代淘金热时期的无赖和暴徒。而在网上,似乎有更多、更聪明且组织更严密的数字不法分子。
这就是为什么学习如何编写Shell脚本的最重要步骤之一是学习如何确保你的脚本是安全的——即使只是用于你的家用电脑或你把旧PC改造成了基于Linux的媒体服务器,运行Plex或类似的软件。
让我们来看看一些基本原则。
了解你调用的工具
以下是一个经典的特洛伊木马攻击:攻击者在 /tmp
目录中放置了一个名为 ls
的脚本,这个脚本会检查调用它的用户ID,然后将所有参数传递给真正的 /bin/ls
。如果它识别到用户ID是root,就会将 /bin/sh
复制到 /tmp
,取一个看似无害的名字,并更改其权限为 setuid root。
编写这样的脚本非常简单。下面是一个即兴版本:
#!/bin/sh
if [ "$USER" = "root" ] ; then
/bin/cp /bin/sh /tmp/.secretshell
/bin/chown root /tmp/.secretshell
/bin/chmod 4666 root /tmp/.secretshell
fi
exec /bin/ls $*
我希望你明白刚才发生了什么。这个简单的小脚本创建了一个shell,这个shell总是为其用户提供root访问权限。可怕的是,更高级的版本会在创建root shell后自我删除,不留下任何痕迹。
由于讽刺应该是讽刺的,我在上述特洛伊木马脚本中演示了如何避免这种危险。永远不要仅仅通过名字调用程序;一定要包含它们的路径。一个包含 ls $HOME
的脚本是在自找麻烦,所以用 /bin/ls $HOME
修正它。
另一个可能出现这种风险的有趣地方是你的 PATH。再次假设你的 PATH 设置如下:
PATH=".:/bin:/usr/bin:$HOME/bin:/usr/local/bin"
95%的情况下,这不会有问题,对 ls
、cp
甚至 date
的调用会按预期执行,因为它们不会在 PATH 中的第一个目录中找到,最终会级联到存储合法二进制文件的 /bin
。但如果你恰好在 /tmp
目录中调用命令会发生什么?在不知不觉中,你实际上调用了特洛伊版本,并再次创建了那个root shell(如果当时你是root用户的话)。
解决方案:要么永远不要将点(.)作为 PATH 中的一个目录(我的建议),要么将其放在链中的最后,而不是第一个。
不要在脚本中存储密码
我承认,在这一点上我并不是最好的榜样,因为我有一些别名实际上会将密码推送到我的复制/粘贴缓冲区,然后调用 ssh
或 sftp
连接到远程计算机。这是一种愚蠢的解决方案,因为它不可避免地意味着我有一个Shell脚本——或者在这种情况下是一个别名文件——其中包含像这样的行:
PASSWORD="froBOZ69"
或者像这样:
alias synth='echo secretpw | pbcopy; sftp adt@wsynth.net'
解决方案:不要这样做。如果你必须这么做,那么至少不要使用如此明显(而且在扫描时容易识别)的变量名。但实际上,找到一个替代工具来完成任务更为明智,安全风险根本不值得冒。
警惕用户输入的内容被调用这是一个微妙的问题,但像下面这样的简单序列中可能存在巨大的安全风险:
echo -n "What file do you seek? "
read name
ls -l $name
如果用户输入了一个恶意的文件名,比如:
. ; /bin/rm -Rf /
后果可能会非常严重,无论脚本是以 root 用户身份还是普通用户身份运行。如果将参数用引号括起来,Bash 提供了一定的保护,因此上面的序列可以通过以下修改来保护:
/bin/ls -l "$name"
但是,如果是这样调用的 eval /bin/ls -l "$name"
,这种保护将不起作用。此外,还有臭名昭著的反引号问题。想象一下用户输入如下内容:
. `/bin/rm -Rf /`
这是另一个风险,因为 ``
是 $( )
的简写,遇到时会启动一个子 Shell。在命令行上,ls
的调用也会由这样的子 Shell 执行。
为了解决这一危险,如果你认为脚本可能会遇到恶意用户,请扫描并清理输入。一个简单的解决方案是:如果输入中遇到非字母数字或少量安全标点符号的字符,就直接报错退出。
不要使用 Shell 脚本作为 CGI 脚本运行 Linux 网络服务器并学习 CGI 脚本?使用 Shell 脚本来实现基本的 CGI 功能不仅很有诱惑力,而且快速且简单。下面是一个显示服务器负载的脚本:
#!/bin/sh
echo "Content-type: text/html"; echo ""
echo "Uptime on the Server:<pre>"
uptime -a
echo "</pre>"
一旦你正确设置了权限,这个脚本就能正常工作。它并不太危险,但如果你想为你的网站做一个类似的自制搜索系统呢?同样,每当你有一个需要从未知用户输入的脚本时,你就增加了许多重大风险因素。
在这种情况下,解决方案是 不要这样做。使用一个已编译的程序来实现安全的功能,或者使用第三方搜索系统,比如 Google Custom Search Engine,以确保最大程度的安全。
聪明地编写代码有很多理由喜欢在 Linux Shell 中编程,其中之一就是它快速且容易进行原型设计。但如果你真的想创建一个安全的计算环境,你需要在编写代码的过程中就注重安全,而不是事后才意识到自己做了一些愚蠢的事情。
一些好的在线资源更深入地探讨了这些话题。可以查看 GitHub 上的 Shell 风格指南 来入门。此外,苹果公司也有一份关于 Shell 脚本安全性的 文档,也非常值得阅读。
小心点!花点额外的时间确保你的脚本能够防范已知的重大风险,绝对是值得的。
阅读完毕,很棒哦!
上一篇:如何写gdb命令脚本
下一篇:基础编程学习组