【问题标题】:Is there a way to execute php code in a sandbox from within php有没有办法从 php 中在沙箱中执行 php 代码
【发布时间】:2010-09-24 09:28:30
【问题描述】:

我想从 php 执行一个 php 脚本,它将使用不同的常量和已定义的不同版本的类。

是否有一个沙盒 php_module 我可以:

sandbox('script.php'); // run in a new php environment

而不是

include('script.php'); // run in the same environment

或者proc_open() 是唯一的选择吗?

PS:该脚本无法通过网络访问,因此 fopen('http://host/script.php') 不是一个选项。

【问题讨论】:

    标签: php module sandbox


    【解决方案1】:

    runkit,但如果您不需要主进程和子进程之间的任何交互,您可能会发现只通过命令行调用脚本(使用shell_exec)更简单。

    【讨论】:

    • 关于runkit;根据描述,它似乎不能很好地沙箱化,或者我应该说简单。您可以禁止功能,但我宁愿禁止所有功能,但提供的列表中的功能除外。如果用户需要某个功能,我可以根据要求手动评估其安全性。似乎唯一的方法是编写一个定制的解释器。如果速度是一个问题,您可以将其 AST 转换为 PHP 或其他语言,这实际上是我现在要做的,因为我找不到现成的解决方案。干杯!附言。是的,我看到这个Q很旧。 Ds.
    • 嗯 .. 祝你好运找到可以将 PHP 解析为 AST 的东西;) 不过我同意你的观点。
    • FYI runkit 似乎已被放弃,如果您想在现代版本的 PHP 上运行它,您可能需要编译 CVS 版本或修补版本之一 (github.com/tricky/runkit) /跨度>
    【解决方案2】:

    这是 GitHub 上的一个课程,它可能会有所帮助,处于早期阶段,但看起来很有希望。

    https://github.com/fregster/PHPSandbox

    【讨论】:

      【解决方案3】:

      另外,你应该看看backtick operator

      $sOutput = `php script_to_run.php`;
      

      这将允许您检查正在运行的脚本的输出。但是请注意,脚本将以您拥有的权限运行,但您可以通过在 Linux 上使用 sudo 来规避这一点。

      此方法还假定您已安装 PHP CLI,但并非总是如此。

      【讨论】:

        【解决方案4】:

        Runkit_Sandbox - 你可以让它工作,它是一个 PHP 扩展。我会说要走的路。

        但您可能需要自己创建一个“沙盒”,例如通过重置您使用的超全局变量的全局变量状态。

        class SandboxState
        {
            private $members = array('_GET', '_POST');
            private $store = array();
            public function save() {
                foreach($members as $name) {
                    $this->store[$name] = $$name;
                    $$name = NULL;
                }
            }
            public function restore() {
                foreach($members as $name) {
                    $$name = $this->store[$name];
                    $this->store[$name] = NULL;
                }
        
            }
        }
        

        用法:

        $state = new SanddboxState();
        $state->save();
        
        // compile your get/post request by setting the superglobals
        $_POST['submit'] = 'submit';
        ...
        
        // execute your script:
        $exec = function() {
            include(func_get_arg(0)));
        };
        $exec('script.php');
        
        // check the outcome.
        ...
        
        // restore your own global state:
        $state->restore();
        

        【讨论】:

          【解决方案5】:

          动态插件函数执行,允许加载的文件和函数执行任何它想要的,但是它只能接受和返回可以是json_encode'ed的变量。

          function proxyExternalFunction($fileName, $functionName, $args, $setupStatements = '') {
            $output = array();
            $command = $setupStatements.";include('".addslashes($fileName)."');echo json_encode(".$functionName."(";
            foreach ($args as $arg) {
              $command .= "json_decode('".json_encode($arg)."',true),";
            }
            if (count($args) > 0) {
              $command[strlen($command)-1] = ")";//end of $functionName
            }
            $command .= ");";//end of json_encode
            $command = "php -r ".escapeshellarg($command);
          
            exec($command, $output);
            $output = json_decode($output,true);
          }
          

          外部代码完全被沙盒化,您可以通过 sudo -u restricedUser php -r ... 应用您想要的任何权限限制。

          【讨论】:

            【解决方案6】:

            我为此目的开发了一个 BSD 许可的沙盒类。它利用 PHPParser 库来分析沙盒代码,根据用户可配置的白名单和黑名单对其进行检查,并具有广泛的配置选项以及合理的默认设置。根据您的需要,您可以轻松地重新定义在沙盒代码中调用的类并将它们路由到不同的类。

            该项目还包括一个沙盒工具包(仅在您的本地机器上使用!),可用于试验沙盒设置,以及完整的手册和 API 文档。

            https://github.com/fieryprophet/php-sandbox

            【讨论】:

            • 无论如何都可以使用你的类而不通过作曲家安装它。我不想将它安装在实时服务器上。只使用普通类?
            【解决方案7】:

            我知道它不是 100% 相关的主题,但可能对某人有用 n__n

            function require_sandbox($__file,$__params=null,$__output=true) {
            
                /* original from http://stackoverflow.com/a/3850454/209797 */
            
                if($__params and is_array($__params))
                 extract($__params);
            
                ob_start();
                $__returned=require $__file;
                $__contents=ob_get_contents();
                ob_end_clean();
            
                if($__output)
                 echo $__contents;
                else
                 return $__returned;
            
            };
            

            【讨论】:

            • 如果 $__file 试图定义已经定义的常量,它就不起作用。如果 $__file 使用 global 关键字或 $GLOBALS 数组来引用全局范围内的变量,它也可能会破坏全局变量。
            • 我更新了代码,现在就试试吧希望在全球范围内:D
            • 这更像是一个模板需求,而不是真正的沙盒
            猜你喜欢
            • 1970-01-01
            • 2012-06-03
            • 2020-08-14
            • 1970-01-01
            • 2012-05-22
            • 2012-01-12
            • 1970-01-01
            • 2020-02-14
            • 2017-06-20
            相关资源
            最近更新 更多