我接管了一些在php中使用eval()函数的webgame代码。我知道这可能是一个严重的安全问题,所以在我决定是否修改代码的这一部分之前,我想要一些帮助审查检查其参数的代码。目前我已经从游戏中删除了这部分代码,直到我确信它是安全的,但功能的丢失并不理想。我宁愿保证这一点,而不是重新设计整个段以避免使用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变量的引用。
那么:有没有漏洞留在这里?我是否误解了上面的任何正则表达式?最后,有没有任何方法可以安全地证明这一点而不排除(字符?要输入的字符串理想情况下是一个数学公式,并允许(允许操作操作顺序,这是目前不可能的。
答案 0 :(得分:3)
评估VM中的代码 - 请参阅Runkit_Sandbox
或者为您的数学创建解析器。我建议你使用内置的tokenizer。您需要迭代令牌并跟踪括号T_DNUMBER
,T_LNUMBER
,运算符和T_CONSTANT_ENCAPSED_STRING
。忽略其他一切。然后,您可以安全地评估结果表达式。
快速谷歌搜索显示this library。它完全符合您的要求......
使用tokenizer的一个简单示例:
$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}");
(test)
仅当输入是有效的数学表达式时才会起作用。否则,你的eval`d代码中会出现一个解析错误,因为空括号和类似的东西。如果您还需要处理它,那么清理另一个循环中的输出表达式。这应该照顾大多数无效部分:
while(strpos($expr, '()') !== false)
$expr = str_replace('()', '', $expr);
$expr = trim($expr, '+-/*');
答案 1 :(得分:1)
匹配允许的内容而非删除某些字符是最好的方法。
我看到你没有过滤可用于执行系统命令的`(反引号)。上帝只知道还有什么不能通过尝试消毒字符串而被阻止......无论发现多少个洞,都无法保证不会有更多。
假设您的语言不是很复杂,那么在不使用eval的情况下自己实现它可能并不困难。
答案 2 :(得分: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 );