避免PHP中代码注入的最佳方法

时间:2020-03-05 18:46:16  来源:igfitidea点击:

我的网站最近遭到了一个无辜的代码的攻击:

<?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
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规则始终会对其进行清理。在这里,我们没有在将页面GET变量传递到include之前对其进行清理。在包含文件之前,应执行基本检查以查看文件在服务器上是否存在。

回答

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

$whitelist = array('home', 'page');

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

回答

清理输入的另一种方法是确保仅允许使用的字符(没有" /","。",":",...)在其中。但是,不要对不良字符使用黑名单,而对允许的字符使用白名单:

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

...紧接着是file_exists。

这样,我们可以确保仅执行要执行的脚本(例如,这将排除" blabla.inc.php",因为不允许使用"。")。

注意:这是一种" hack",因为这样用户可以执行" h.o.m.e",并且会显示" home"页面,因为它所做的只是删除所有禁止的字符。这并不是要阻止想要在页面上添加可爱内容的"聪明人",但它会阻止人们做真正不好的事情。

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

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

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

但是请记住,查询字符串中不允许使用" http"。网站在某些情况下(可能是在填写表格时)可能需要它。

顺便说一句:如果我们能读德语:我也有一篇关于该主题的博客文章。

回答

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

不要重新发明轮子。使用框架。他们中的任何一个总比没有好。最初在学习上的投入几乎可以立即收回。

回答

佩克,除了sql注入,甚至还有不同类型的代码注入,还有很多事情要担心。现在也许是个很好的时机,对一般的Web应用程序安全性有进一步的了解。

从上一个关于从桌面开发到网络开发的问题开始,我写道:

The OWASP Guide to Building Secure Web Applications and Web Services should be compulsory reading for any web developer that wishes to take security seriously (which should be all web developers). There are many principles to follow that help with the mindset required when thinking about security.
  
  If reading a big fat document is not for you, then have a look at the video of the seminar Mike Andrews gave at Google a couple years back about How To Break Web Software.

回答

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

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

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

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

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

回答

@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()