您现在的位置是:网站首页>技术百科技术百科

编写安全的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%的情况下,这不会有问题,对 lscp 甚至 date 的调用会按预期执行,因为它们不会在 PATH 中的第一个目录中找到,最终会级联到存储合法二进制文件的 /bin。但如果你恰好在 /tmp 目录中调用命令会发生什么?在不知不觉中,你实际上调用了特洛伊版本,并再次创建了那个root shell(如果当时你是root用户的话)。

解决方案:要么永远不要将点(.)作为 PATH 中的一个目录(我的建议),要么将其放在链中的最后,而不是第一个。

不要在脚本中存储密码

我承认,在这一点上我并不是最好的榜样,因为我有一些别名实际上会将密码推送到我的复制/粘贴缓冲区,然后调用 sshsftp 连接到远程计算机。这是一种愚蠢的解决方案,因为它不可避免地意味着我有一个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 脚本安全性的 文档,也非常值得阅读。

小心点!花点额外的时间确保你的脚本能够防范已知的重大风险,绝对是值得的。

阅读完毕,很棒哦!

文章评论

站点信息

  • 网站地址:www.xiaodahan.com
  • 我的QQ: 3306916637