我正在使用php中的浏览器shell(它使用build in exec函数或perl或python中的cgi脚本之一),我想允许对guest用户进行有限的shell访问。我有这个功能来清理用户命令:
private function validate_command($command) {
$commands = array('echo', 'cat', 'ls', 'find', 'cd', 'grep');
$cmd_re = "(" . implode("|", $commands) . ")";
$re = "/^\s*($cmd_re|xargs\s*$cmd_re)/";
$separators = "/(\||&&|\|\||;)/";
$parts = preg_split($separators, $command, null, PREG_SPLIT_DELIM_CAPTURE);
$result = array();
foreach ($parts as $part) {
if (preg_match($separators, $part)) {
$result[] = $part;
} else if (!preg_match($re, trim($part))) {
$last = array_pop($commands);
$message = "guest user can only execute: " .
implode(", ", $commands) . " and " . $last;
throw new Exception($message);
} else {
// escapeshellcmd is not use here because it escape quotes
// and * ? so you can't use find . -name "*.js"
$result[] = preg_replace('/(\\\\|`|\$\()/', "\\\\$1", $part);
}
}
return implode($result);
}
它适用于这样的命令:
find projects/jcubic -name '*.js' | xargs grep jcubic
但不允许执行find / | xargs rm
或rm *
并转义$(
和`
这个功能安全吗?是否可以利用它来执行不允许的命令?如果不安全我怎样才能安全?这很难吗?
更新 @ jh1711评论之后的更新功能:
private function validate_command($command) {
$commands = array('echo', 'cat', 'ls', 'find', 'cd', 'grep');
$cmd_re = "(" . implode("|", $commands) . ")";
$re = "/^\s*($cmd_re|xargs\s*$cmd_re)/";
$separators = "/(&&|\|\||\||;)/";
$parts = preg_split($separators, $command, null, PREG_SPLIT_DELIM_CAPTURE);
$result = array();
foreach ($parts as $part) {
if (!preg_match($re, trim($part)) && !preg_match($separators, $part)) {
$message = "guest user can only execute: " .
implode(", ", $commands) . " and xargs";
throw new Exception($message);
} else if (preg_match('/(>|`|\$\()/', $part)) {
throw new Exception("guest user can't use redirect to write to files" .
" or execute subshell");
} else {
$result[] = $part;
}
}
return implode($result);
}
还有什么我想念的吗?