5

我正在接管一些在 php中使用eval()函数的网页游戏代码。我知道这可能是一个严重的安全问题,所以在我决定是否取消这部分代码之前,我需要一些帮助来审查检查其参数的代码。目前我已经从游戏中删除了这部分代码,直到我确定它是安全的,但功能的损失并不理想。我宁愿安全证明这一点,也不愿重新设计整个段以避免使用 eval(),假设这样的事情是可能的。据称可以防止恶意代码注入的相关代码片段如下。$value 是一个用户输入的字符串,我们知道它不包含“;”。

1 $value = eregi_replace("[ \t\r]","",$value);
2 $value = addslashes($value);
3 $value = ereg_replace("[A-z0-9_][\(]","-",$value);
4 $value = ereg_replace("[\$]","-",$value);
5 @eval("\$val = $value;");

到目前为止,这是我的理解:

1) 从 $value 中删除所有空格

2)转义数据库调用需要它的字符(我不清楚为什么需要它)

3) 查找紧跟 \ 或 ( 的字母数字字符,并将它们的组合替换为 -。大概这是为了删除字符串中任何类似函数调用的内容,尽管我不清楚为什么它还会删除前面的字符,这就是为什么在第 2 行明确添加它们之后,它也会删除 \。

4) 用 - 替换所有 $ 实例,以避免在字符串中出现任何类似对 php 变量的引用。

那么:这里有没有留下任何漏洞?我误解了上面的任何正则表达式吗?最后,有没有办法在不排除 ( 字符的情况下进行安全证明?要输入的字符串理想地是一个数学公式,并且允许 ( 将允许操作操作顺序,这目前是不可能的。

4

3 回答 3

4
  1. 评估 VM 内的代码 - 请参阅Runkit_Sandbox

  2. 或者为您的数学创建一个解析器。我建议你使用内置的tokenizer。您需要迭代标记并跟踪括号、、、、T_DNUMBER运算T_LNUMBER符和可能T_CONSTANT_ENCAPSED_STRING的 . 忽略其他一切。然后您可以安全地评估结果表达式。

  3. 一个快速的谷歌搜索显示了这个库。它完全符合您的要求...


使用标记器的简单示例:

$tokens = token_get_all("<?php {$input}");
$expr = '';

foreach($tokens as $token){

  if(is_string($token)){

    if(in_array($token, array('(', ')', '+', '-', '/', '*'), true))
      $expr .= $token;

   continue;   
  }

  list($id, $text) = $token;

  if(in_array($id, array(T_DNUMBER, T_LNUMBER)))
    $expr .= $text;
}

$result = eval("<?php {$expr}");

测试

这仅在输入是有效的数学表达式时才有效。否则你会在你的 eval`d 代码中得到一个解析错误,因为空括号和类似的东西。如果您也需要处理此问题,请在另一个循环中清理输出表达式。这应该处理大部分无效部分:

while(strpos($expr, '()') !== false)
  $expr = str_replace('()', '', $expr);

$expr = trim($expr, '+-/*');
于 2013-07-15T00:42:22.797 回答
2

匹配允许的内容而不是删除某些字符是这里最好的方法。

我看到您没有过滤可用于执行系统命令的`(反引号)。天知道还有什么不能通过尝试对绳子进行消毒来防止......无论找到多少洞,都不能保证不会有更多。

假设您的语言不是很复杂,那么在不使用 eval 的情况下自己实现它可能并不难。

于 2013-07-15T00:42:51.093 回答
0

下面的代码是我们自己尝试回答的同类问题:

$szCode = "whatever code you would like to submit to eval";

/* First check against language construct or instructions you don't allow such as (but not limited to) "require", "include", ..." : a simple string search will do */
if ( illegalInstructions( $szCode ) )
{
   die( "ILLEGAL" );
}

/* This simple regex detects functions (spend more time on the regex to
   fine-tune the function detection if needed) */
if ( preg_match_all( '/(?P<fnc>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*) ?\(.*?\)/si',$szCode,$aFunctions,PREG_PATTERN_ORDER ) )
{
    /* For each function call */
    foreach( $aFunctions['fnc'] as $szFnc )
    {
        /* Check whether we can accept this function */
        if ( ! isFunctionAllowed( $szFnc ) )
        {
            die( "'{$szFnc}' IS ILLEGAL" );
        }   /* if ( ! q_isFncAllowed( $szFnc ) ) */
    }
}
/* If you got up to here ... it means that you accept the risk of evaluating
   the PHP code that was submitted */
eval( $szCode );
于 2017-03-26T10:45:47.313 回答