返回介绍

4.10 文件处理相关的问题

发布于 2024-10-10 22:16:32 字数 8914 浏览 0 评论 0 收藏 0

Web 应用会通过多种多样的形式和文件打交道。而本节的主题就是处理文件时可能产生的 安全隐患。

在有些 Web 应用中,外界能够通过传入参数的形式来指定服务器中的文件名。比如由外界参数来指定模板文件的情况。这样的 Web 应用可能会招致以下攻击。

  • 非法访问 Web 服务器内的文件(目录遍历)
  • 调用 OS 命令(OS 命令注入)

其中,目录遍历漏洞将在 4.10.1 节中讲述。此外,通过目录遍历攻击有时还能够执行 OS 命令,不过这里我们将此问题归为 OS 命令注入的范畴并在 4.11 节中讲述。

另外,如果数据文件或配置文件被保存在公开目录中,就可能会被外界浏览而造成信息泄漏。详情将在 4.10.2 节中讲述。

4.10.1 目录遍历漏洞

概要

Web 应用中允许外界以参数的形式来指定服务器上的文件名时,如果没有对文件名进行充分的校验,就可能会造成意料之外的问题,比如文件被浏览、篡改或删除。该安全隐患被称为目录遍历漏洞。

目录遍历漏洞会造成以下影响。

  • 浏览 Web 服务器中的文件
    • 泄漏重要信息
  • 篡改或删除 Web 服务器中的文件
    • 篡改网页内容,散布谣言或恶意诽谤他人
    • 布下圈套将用户诱导至恶意网站
    • 删除脚本文件或配置文件导致服务器宕机
    • 通过篡改脚本文件从而在服务器上执行任意脚本

目录遍历漏洞的防范策略如下,执行其中一项即可。

  • 避免由外界指定文件名
  • 文件名中不允许包含目录名
  • 限定文件名中仅包含字母和数字

目录遍历漏洞总览

攻击手段与影响

下面我们就来看一下目录遍历攻击的手段与影响。

以下是能够使用 template= 的形式来指定页面模板文件的脚本。

代码清单 /4a/4a-001.php

<?php
  define('TMPLDIR', '/var/www/4a/tmpl/');
  $tmpl = $_GET['template'];
?>
<body>
<?php readfile(TMPLDIR . $tmpl . '.html'); ?>
菜单(以下略)
</body>

常量 TMPLDIR 指定的是存放模板文件的目录名。模板文件名由查询字符串中的 template 指定,并被赋值到变量 $tmpl 中。脚本使用 readfile 函数读取模板文件,然后将其原封不动地放到响应信息中。

下面为模板文件的示例。

代码清单 /4a/tmpl/spring.html

你好,已经是春天了呢。<br>

通过以下 URL 执行脚本就能够读取上述模板文件。

http://example.jp/4a/4a-001.php?template=spring

图 4-92 示例脚本的执行例

此时,脚本中被拼接成的文件名如下所示。

正常情况下拼接成的文件名

/var/www/4a/tmpl/spring.html

接下来我们就来看一下如何对其展开攻击。使用以下 URL 执行示例脚本。

http://example.jp/4a/4a-001.php?template=../../../../etc/hosts%00

图 4-93 显示了 Linux 的配置文件内容

页面中显示的为 Linux 的配置文件 /etc/hosts 的内容。也就是说,通过目录遍历攻击能够浏览操作系统的配置文件。此时,脚本内被拼接成的文件名如下所示。其中 [NUL] 为空字节(字符编码为 0 的字符)57 。

57 正如 1. 4.2 节中介绍的那样,空字节在 C 语言中表示字符串的结束。

攻击时拼接成的文件名

/var/www/4a/tmpl/../../../../etc/hosts[NUL]

.html

由于 ../ 表示上层目录,空字节又会迫使文件名字符串结束,因此,将此文件名标准化后,实际被访问的文件名即为如下内容。

标准化后的文件名

/etc/hosts

因此,最终页面显示的是 etc/hosts 文件的内容。

由此可见,一旦 Web 应用中存在目录遍历漏洞,攻击者就能够随意访问服务器上的任何文件。

不过上面的例子仅仅展示了读取文件的情况,其实,依据应用的内部实现,有时还能够进行覆盖或删除文件等操作,从而造成数据被篡改。

此外,一旦攻击者能够通过目录遍历来编辑 PHP 等脚本文件,就能将编辑后的脚本在 Web 服务器上运行,从而也就相当于能够执行任意脚本。这时攻击造成的影响与 OS 命令注入(参考 4.11 节)相同,即能使计算机下载恶意程序或对系统进行非法操作等。

专栏:从脚本源码开始的一连串的信息泄漏

通过目录遍历攻击访问 Web 服务器上的文件时需要知道文件名。虽然 /etc/hosts 是操作系统中固定的文件名,但由于一般来说第三方无法得知存储个人信息等文件的文件名,因此有人就会觉得不会有遭到攻击的风险。

然而,还有一种攻击手段为,先通过目录遍历攻击查看脚本的源代码,然后再使用 open 语句等来调查被指定文件的文件名。其中,在试验环境的“/4a/ 菜单”中点击“3. 4a-001: 目录遍历(脚本:显示源码)”链接,就能够查看脚本源码。执行后虽然浏览器上不会显示 PHP 的源码,但通过查看 HTML 的源码就能够确认 PHP 脚本。

安全隐患的产生原因

当应用满足以下 3 个条件时,就有可能产生目录遍历漏洞。

  • 外界能够指定文件名
  • 能够使用绝对路径或相对路径等形式来指定其他目录的文件名
  • 没有校验是否允许访问拼接后的文件名

如果从开发者的角度来考虑的话,笔者觉得,漏洞的产生可能是因为开发者没有考虑到“外界能够指定其他目录”的可能性。

由于目录遍历漏洞的产生需要同时满足以上 3 个条件,因此,只要使其中任意一项无法满足也就能够将漏洞消除。

对策

概要中已经简单介绍过消除目录遍历漏洞的方法,即实施以下任一项。

  • 避免由外界指定文件名
  • 文件名中不允许包含目录名
  • 限定文件名中仅包含字母和数字

下面我们就对以上方法进行详细说明。

  • 避免由外界指定文件名

    如果能够避免文件名由外界指定,就能从根本上解决目录遍历漏洞。具体方法有如下几种。

    • 将文件名固定
    • 将文件名保存在会话变量中
    • 不直接指定文件名,而是使用编号等方法间接指定

    而至于这些方法的具体操作,此处就不再逐一介绍。

  • 文件名中不允许包含目录名

    如果文件名中不包括目录名(包括 ../),就能确保应用中只能访问给定目录中的文件,从而也就消除了目录遍历漏洞产生的可能性。

    表示目录的字符 /、\、: 等因操作系统而异,不同的操作系统应当采用不同的程序库。在 PHP 中则能够使用 basename 函数。

    basename 函数会接收带有目录的文件名(也包括 Windows 的盘符),并返回末尾的文件名部分。例如 basename('../../../../etc/hosts') 返回的结果即为 hosts。

    利用 basename 函数的对策示例如下所示。

    代码清单 /4a/4a-001b.php

    <?php
      define('TMPLDIR', '/var/www/4a/tmpl/');
      $tmpl = basename($_GET['template'])
    
    ;
    ?>
    <body>
    <?php readfile(TMPLDIR . $tmpl . '.html'); ?>
    菜单(以下略)
    </body>
    

    专栏:basename 函数与空字节

    PHP 的 basename 函数在处理时不会删除空字节 58 ,因此,即使使用了 basename 函数也还是有可能会出现文件扩展名被更改的情况。比如,假设以下脚本中的扩展名被指定为 txt。

    $file = basename($path) . '.txt';
    

    这时,如果外界传入的文件名为 a.php%00(已经过百分号编码),就会生成如下文件名。

    图 4-94 上述脚本生成的文件名

    然而,由于 Windows 或 Unix 等多数操作系统中都使用 C 语言形式的字符串,因此文件名中有空字节(\0)时就会被视为文件名结束。这样一来,实际打开的文件就变成了 a.php,应用中指定的 txt 扩展名则被忽略了。

    由此可见,文件名由外界传入的情况下,有必要对文件名进行校验以确保其中不包含空字节。

  • 限定文件名中仅包含字母和数字

    如果能够限制文件名的字符种类仅为字母和数字,那么用于目录遍历攻击的字符就会无法使用,因此这个方法也能作为目录遍历的防范策略。

    下面我们就来尝试在 4a-001.php 中实施这一方法,如下所示。

    代码清单 /4a/4a-001c.php

    <?php
      define('TMPLDIR', '/var/www/4a/tmpl/');
      $tmpl = $_GET['template'];
      if (! preg_match('/\A[a-z0-9]+\z/ui', $tmpl)) {
        die('remplate 仅能指定字母或数字 ');
      }
    ?>
    <body>
    <?php readfile(TMPLDIR . $tmpl . '.html'); ?>
    菜单(以下略)
    </body>
    
    

    这里通过 preg_match 匹配正则表达式确认了文件名变量 $tmpl 中仅包含字母和数字。 ereg 函数由于不能正确处理空字节(非二进制安全),因此不能被用于本方法。详情请参考 4.2 节。

58 确认于 PHP5.3.5。

总结

本节讲述了访问文件的处理中容易混入的目录遍历漏洞。解决目录遍历漏洞的最佳方法是不允许外界指定文件名。因此推荐在设计阶段就开始探讨是否能够做到这一点。

4.10.2 内部文件被公开

概要

Web 服务器的公开目录中有时会放置对外保密的文件。这种情况下,外界一旦得知文件的 URL,就能够浏览这些内部文件。

内部文件被公开会造成如下影响。

  • 重要信息被泄漏

防范内部文件被公开的对策为,不在公开目录中放置内部文件。或者保险起见,也可以直接禁用目录列表功能。这一点在后面会进行详述。

内部文件被公开总览

攻击手段与影响

首先使用以下 URL 浏览本书提供的虚拟机。

http://example.jp/4a/data/

如下图所示,页面上列出了目录内的所有文件。

图 4-95 目录内的文件一览

像上面这样,使用 URL 指定目录名时,页面上会罗列出目录中的所有文件,这一功能就叫作目录列表(Directory Listing)。

点击页面上的 user.txt 链接,此时页面显示如下。

图 4-96 文件内容被显示

如文件名所示,页面上显示了用户信息文件 user.txt 的内容。

虽然这种攻击的手法很简单,但 2004 年以前发生的 Web 网站泄漏用户个人信息的事件多数都是起因于这种攻击模式。

安全隐患的产生原因

导致内部文件被公开的原因为,内部文件被放在了公开目录中。当应用满足以下条件时,放置在公开目录下的文件就能够被外界访问。

  • 文件被放置在公开目录中
  • 有方法得知访问文件的 URL
  • 没有对文件设置访问权限

其中,得知访问文件的 URL 的手段有如下几种。

  • 目录列表功能被设为有效
  • 文件名为日期、用户名或连续数值等能够被推测的值
  • user.dat、data.txt 等常见文件名
  • 通过错误消息或其他安全隐患而得知文件名
  • 被外部网站链接进而被搜索引擎收录

Apache 中可以设置 httpd.conf 或 .htaccess 来限制对文件的访问,但仅仅依靠这些设置来禁止访问文件还是存在风险的。因为设置可能一不注意就会被更改。过去发生的信息泄漏事件中,虽然很多在一开始时也都通过设置限制了文件访问,但是在迁移服务器时限制就有可能会被去除,从而就会导致信息泄露的发生。

对策

防范内部文件被公开的根本性对策为,不将内部文件放置在公开目录下。为了做到这一点,可以采用以下方法。

  • 设计应用程序时,决定存放文件的安全场所
  • 租用服务器时确认能够使用非公开的目录

另外,保险起见还可以将目录列表功能设为无效。其中,Apache 中可以如下编辑 httpd.conf 文件来进行设置。

<Directory 指定路径 >
  Options -Indexes 其他选项
  其他设置
</Directory>

如果租用服务器不允许更改 httpd.conf,可以在公开目录下放置名为 .htaccess 的文件,并进行如下设置。但是,鉴于有些租用服务器厂商可能不允许使用 .htaccess 来更改设置,因此事先一定要对此加以确认。

Options -Indexes

参考:Apache 中隐藏特定文件的方法

如之前所述,为了防止内部文件被公开,原则上应当彻底贯彻不将非公开文件放置在公开目录下的方针。但是,在既有 Web 网站中存在此问题时,可能就无法通过简单的移动文件的方法来解决问题。这种情况下,可以通过设置禁止外界访问特定文件,来姑且进行暂时性的处理。Apache 中 .htaccess 的设置方法如下所示。该示例中设置了禁止外界浏览扩展名为 txt 的文件。详情请参考 Apache 的说明文档。

代码清单 .htaccess

<Files "*.txt">
   deny from all
</Files>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文