PHP 安全地包含文件 + 处理无效参数

Posted

技术标签:

【中文标题】PHP 安全地包含文件 + 处理无效参数【英文标题】:PHP Securely include files + handle invalid parameters 【发布时间】:2018-04-28 17:59:55 【问题描述】:

我遇到了一个小问题。如果参数无效,我想安全地包含基于来自子目录 + 句柄的 $_GET 参数的文件。

 <?php
if(isset($_GET['p']) && $_GET['p'] == 'fahrzeuge')
        include 'includes/cars.php';
    
  if(isset($_GET['p']) && $_GET['p'] == 'impressum')
        include 'includes/impressum.php';
    
    if(isset($_GET['p']) && $_GET['p'] == 'home')
            include 'includes/home.php';
        
      if(isset($_GET['p']) && $_GET['p'] == 'anfahrt')
            include 'includes/anfahrt.php';
        
        if(isset($_GET['p']) && $_GET['p'] == 'about')
                include 'includes/about.php';
            

?>

这是我的代码。对不起,我知道这是解决这个问题的一种菜鸟方式。我该如何改进它?任何建议/帮助将不胜感激

【问题讨论】:

【参考方案1】:

这是最快和最好的方法,我是短代码的粉丝 并从 (HACKBUGZ PHP) 中找到了这个。

您有一个包含数组键数组值的数组。

示例 1

<?php

    $PAGES          = array();
  
    $PAGES = [
       'home'       => 'home.html'
      ,'about'      => 'about.php'
      ,'contact'    => 'somedir/contact.php'
    ];

    @include(substr($PAGES[$_GET['p']] ?? ('home'), 0, 255));

    exit;

?> 

    您可以有不同的查询名称、文件名、文件类型和目录

    如果文件不存在,@ 会捕获包含错误。

    substr($PAGES, 0, 255) 将 uri 削减为 255 个字符(如果你不喜欢这样的话 不做就行了)

    ($PAGES[$_GET['p']] ?? ('home')) 检查查询 (array_key) 是否存在于数组中,如果不存在 'home' 将是默认值 p>

示例 2(无 substr)

<?php

    $PAGES          = array();
  
    $PAGES = [
       'home'       => 'home.html'
      ,'about'      => 'about.php'
      ,'contact'    => 'somedir/contact.php'
    ];

    @include($PAGES[$_GET['p']] ?? ('home'));

    exit;

?> 

【讨论】:

【参考方案2】:

我会使用ternary 来设置一个变量来告诉页面要包含的内容。

这与Ofir Baruch 的回答非常相似,只是要短得多。

$pages = array('about','contact','home');

$p = isset($_GET['p']) && in_array($_GET['p'], $pages)? $_GET['p'] : 'home';
include "includes/$p.php";

基本上,您有一系列可能的页面。在三元中,我们检查是否设置了$_GET['p'] (isset()),并检查它包含的值是否在数组中。如果是,我们将$_GET['p'] 用作$p,如果不是,我们将$p 设置为home,这意味着如果$_GET['p'] 未设置或不设置,home 将始终为默认值根据数组的有效页面。

【讨论】:

【参考方案3】:

设置合法页面数组。检查一次是否设置了$_GET['p'],如果设置了,则将其值(在转义后)分配给变量$p

然后检查请求的页面 ($p) 是否在您的 pages 数组中定义,如果是 - 包括它。

$pages = array('about','contact','home');

$p = 'home'; //Default page
if(isset($_GET['p'])) 
  $p = $_GET['p']; //no need to escape as we compare it to predefined values as @Yoshi suggested
 

if(in_array($p, $pages))
  include 'includes/'.$p.'.php';
 else 
   include 'includes/home.php';

【讨论】:

感谢您的快速回复。如果可行,我将对其进行测试并接受您的问题。或者如果它不能按我想要的方式工作。我会让你知道或问你 当然,没问题。更新我。 真的有必要做htmlspecialchars()并检查一个数组吗?如果$p 包含特殊字符,它就不会加载任何内容,因为该值不会在数组中。如果是页面名称,则必须是文件名,这意味着无论如何都不应该有任何特殊字符,除非我猜可能是一个空格 嘿,它确实有效 + 但如果用户试图修改参数,我也想处理。在这种情况下,页面不包含任何内容并且看起来很糟糕,因此我想包含主页。恐怕这很简单:P 不要转义p,只用它作为数组键,值来包含页面。

以上是关于PHP 安全地包含文件 + 处理无效参数的主要内容,如果未能解决你的问题,请参考以下文章

无效参数类型的 PLSQL 异常处理程序

安全标头无效 - 使用 curl php

处理无效的文件句柄(可能还有其他无效对象)

添加 Flickr API 参数时的 oAuth “无效签名”

为 foreach() 第 48 行提供的参数无效

flutter webView脚本非英文错误:无效参数(字符串):包含无效字符