避免使用include($ _ GET ['page'])

时间:2013-03-03 08:22:03

标签: php security

基本上,我已经在网站上工作了好几个月了,我即将打开它。在开放之前,我正在讨论潜在的安全问题,我已经在网上进行了一些研究,以找出php中的cummon安全问题,我已经知道如何修复它们中的大部分,尽管我确实遇到了问题其中之一:我想避免使用include($_GET['page']),我已经做了一些研究,但没有找到任何真正方便使用的东西,虽然有什么方法可以“保护”我的代码原样吗?登记/> 以下是我编写的用于防止安全问题的内容:

if (!isset($_GET['page'])) 
{
echo redirect_tempo(500, 'index.php?page=home');    
}
    elseif ($_GET['page']=="index") 
    {
    echo redirect_tempo(500, 'index.php?page=home');        
    }
        elseif (file_exists($_GET['page'].".php"))
        {
        require $_GET['page'].'.php';
        }
            else 
            {
            echo redirect_tempo(500, 'index.php?page=404');
            }

请注意,redirect_temp()基本上只是header()

这是否足够,我可以改进它,还是只需要完全改变它?

7 个答案:

答案 0 :(得分:3)

这部分很危险:

elseif (file_exists($_GET['page'].".php"))

我可以给路径"../../../../etc/passwd"(我知道,这有点旧,但它可能是任何东西)并且它会读取文件(给予足够的权限)。

一个简单的解决方法可能是:

elseif (file_exists(basename($_GET['page']) . ".php"))

不要忘记对实际require

应用相同的内容
require basename($_GET['page']) . '.php';

您还可以进一步申请basename(),这样您就不必再申请该功能

另请参阅:basename

答案 1 :(得分:0)

做你的方法没什么不对。只需添加一些基本验证,就知道恶意用户不会尝试访问其他路径。

我建议验证字符串中没有斜杠和点(因为Windows中的../或/或\等路径)。甚至可能在最后对.PHP进行硬编码以防止访问其他文件类型。

if (strstr($_GET['page'], ".") || strstr($_GET['page'], "/") || strstr($_GET['page'], "\\")
{
    echo "error";
    exit;
}

include($_GET['page'] .".php");

答案 2 :(得分:0)

继续我的评论,我会做这样的事情。

switch($_GET['page']) {
    case 'index' :
        redirect_tempo(500, 'index.php?page=home');
    break;
    ........
    default :
        die('NO!');
    break;
}

然而,这不是解决这个问题的最好方法。

答案 3 :(得分:0)

您的代码看起来不错。但是如果你在使用前验证你的GET值会更好。您可以检查它是仅数字还是仅限字母或字母数字。它可以是单个单词或多个单词。根据您的要求检查。

答案 4 :(得分:0)

这将包括所有允许的页面,因此$ _GET ['page'] ==搜索将包含search.php,但$ _GET ['page'] ==某些内容将包含home.php:]

$allowed_pages = array('home', 'search', 'signup', 'signin', 'loggedin');
if(in_array($_GET["page"], $allowed_pages)) {
  $page = $_GET["page"]; 
} else { 
  $page = "home"; 
}
  $page = str_replace('/', '', $page);

if(file_exists("page_includes/$page.php")) {
  include("page_includes/$page.php");
} else {
  include("page_includes/home.php");
}

答案 5 :(得分:0)

我使用白名单:

$all_pages = array(
    'index' => 'index.php',
    'about' => 'misc/about.php',
    '404' => '404.php',
    ...
);
function reverse($filename) {
    /* maps filenames to page names */
    return preg_replace('#/pages/(.*).php#', '$1', $filename);
}
/* add all php files in pages/ directory to $all_pages */
foreach (glob("pages/*.php") as $filename) {
    $all_pages[reverse($filename)] = $filename;
}

/* for debugging: make sure this only prints stuffs you want to include */
/* var_dump($all_pages); */

/* the actual check is simple */
$page_name = isset($_GET['page']) ? $_GET['page'] : "index";
$include_name = isset($all_pages[$page_name]) ? $all_pages[$page_name] : "404";
require $include_name;

答案 6 :(得分:0)

很多这些答案都忘记了null-byte attacks。追加" .php"防止像../../../../../etc/passwd这样的东西在许多部署中都不起作用。此问题仅在PHP 5.3.4中正确修复。