PHP $POST动态变量名称安全问题


php $POST dynamic variable names security concerns

我正在考虑做一个循环来收集我所有的 $_POST 变量并将它们分配给动态命名的变量。像这样的东西(未经测试(

 for($i; $i <= $_POST[].length; $i++){
  ${$_POST[i]} = $_POST[i]
  }

但我想知道这样的事情的安全性。然后,这将在系统中为发送到页面的每位帖子数据创建一个变量。即使我编写的脚本没有引用它,该变量也会损坏吗?这是我应该完全避免的事情吗?我有一些页面发送了相当多的变量,像这样的脚本会阻止大量的写作,但它足够安全吗?

是的,可能存在安全风险。

假设您有一个$is_admin前面的代码中定义的变量,该变量为某人提供了管理员功能。 如果有人发布到该页面

$_POST['is_admin'] = true;

那么$is_admin现在是真的。不好。

使用$_POST有什么问题?

是的,可能存在安全问题/问题,例如可以覆盖任何已经设置的局部变量,如数据库、配置值等。

所以应该避免这样的事情:

$yourImportantVar = 'Something relies on this';
//User POSTS yourImportantVar=overwritten
foreach ($_POST as $key => $value) {
    $$key = $value; 
}
echo $yourImportantVar; //overwritten 

但是,如果你想实现一个循环来保存代码块,你可以创建一个允许的数组,你循环访问并从$_POST中提取出值。

foreach (array(
    'name',
    'address',
    'somethingelse',
    'ect'
) as $key) {
    $$key = isset($_POST[$key]) ? $_POST[$key] : null;
}

对于安全性和可维护性来说,这是一个非常糟糕的主意。简化示例为什么...

<?php
if (someRandomSessionCheck()) {
    $isAdminUser = true;
}

if ($isAdminUser) {
    // give access to everything
}
?>

有人可以使用变量"isAdminUser=1"发布到页面,并且可以访问所有内容。

这是一个坏主意的另一个原因是您无法从脚本中清楚地看到创建变量的位置。这会降低脚本的可维护性。如果您现在想要运行脚本,但需要从其他地方而不是 POST 获取数据,该怎么办?

目前我能想到的唯一问题是当它覆盖作用域中的现有变量时。这可能非常不安全,具体取决于您如何处理它。考虑变量是您正在执行HTTP请求的URL。或者更糟糕的是,一些标志变量访问代码的某些关键部分。

我将发布一个关于HTTP请求的示例:

<?php
    $url = "http://safe/url/to/POSTto";
    $var = array("url" => "http://www.mysite.com/url"); //assume this is $_POST
    foreach($var as $key => $value){
        ${$key} = $value;
    }
    //now upon the HttpRequest, your site can receive the (critical) data which was actually meant for the safe site.
?>

编辑:@Galen已经发布了我所说的标志变量,所以可能我不需要发布任何示例来突出问题。

PHP 有一个功能(松散地使用术语(称为 register_globals 。它已被弃用(PHP 5.3(和删除(PHP 5.4(,但它反映了您正在寻找的功能。它执行与 PHP 函数 extract() 相同的操作,后者使用键的名称和匹配数组值的值设置当前范围内的变量。这绝对是一种安全风险。考虑身份验证检查不佳的示例:

if($is_logged_in) {
    // Allow execution of destructive actions
}

如果启用了此功能(或您模仿了此功能(,恶意用户将能够设置变量$is_logged_in并绕过登录屏幕。不用担心节省打字。如果您需要在文件开头复制并粘贴这样的代码块:

$something = $_POST['something'];
$another   = $_POST['another'];
$stuff     = $_POST['stuff'];
//etc.

不仅更安全,而且当开始使用未声明的变量时,它不会让开发人员(他们不希望register_globals(感到困惑。此外,PHP已经删除了它并且有很多反对使用它的论据这一事实应该足以证明这一点。

 <?php
/* Suppose that $var_array is an array returned from
  wddx_deserialize */
 $size = "large";
 $var_array = array("color" => "blue",
               "size"  => "medium",
               "shape" => "sphere");
 extract($var_array, EXTR_PREFIX_SAME, "wddx");
 echo "$color, $size, $shape, $wddx_size'n";
  ?>

请检查此内容。使用循环要做的事情相同。可能对你有所帮助

你基本上是在实现extract($_POST, EXTR_OVERWRITE)它将覆盖任何已经存在的变量。该手册已经警告以您的方式使用extract

不要对不受信任的数据使用extract(),例如用户输入(即 $_GET$_FILES等(。如果您这样做,例如,如果要运行暂时依赖于register_globals的旧代码,请确保使用非覆盖extract_type值之一(如 EXTR_SKIP(,并注意应按照 php.ini 中variables_order中定义的相同顺序进行提取。

这可能导致覆盖基本和敏感的变量,包括那些不能真正直接修改的变量,如$_SESSION$_SERVER$GLOBALS

POST /foo.php HTTP/1.1
Content-Type: application/x-www-urlencoded
_SESSION[user]=admin

这将具有与$_SESSION = array('user'=>'admin')相同的效果。