将上传的图像放在公共文件夹中是否安全?

min*_*gos 16 php security zend-framework image

我刚刚与我的队友讨论过用户上传图片在图库中的位置.我希望对我们建议的方法有更广泛的了解.

我的队友写了一个控制器+动作,它调用file_get_contents放在一个文件夹中的图像文件,该文件夹不能用于公共浏览(即public_html服务器外部),并通过标题回显它.这是安全的,但由于我们使用Zend Framework,它也会慢速爬行 - 由于执行引导程序的查询,每次调用图像控制器都会花费大约500ms的延迟.这很烦人,因为图片库视图同时显示超过20个图像.

简而言之,相关代码将是:

class ImageController extends Zend_Controller_Action {
    public function showAction () {
        $filename = addslashes($this->_getParam('filename'));
        if(!is_file($filename)) {
            $filename = APPLICATION_PATH.'/../public/img/nopicture.jpg';
        }
        $this->_helper->viewRenderer->setNoRender(true);
        $this->view->layout()->disableLayout();
        $img = file_get_contents($filename);
        header('Content-Type: image/jpeg');
        $modified = new Zend_Date(filemtime($filename));
        $this->getResponse()
             ->setHeader('Last-Modified',$modified->toString(Zend_Date::RFC_1123))
             ->setHeader('Content-Type', 'image/jpeg')
             ->setHeader('Expires', '', true)
             ->setHeader('Cache-Control', 'public', true)
             ->setHeader('Cache-Control', 'max-age=3800')
             ->setHeader('Pragma', '', true);
        echo $img;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在视图中,我们只需调用:

<img src="<?php echo $this->url(array('controller' => 'image', 'action' => 'show', 'filename' => PATH_TO_HIDDEN_LOCATION.'/filename.jpg')); ?>" />
Run Code Online (Sandbox Code Playgroud)

我有一个不同的方法:我更喜欢将原始图像保存在隐藏位置,但是一旦请求它们,将它们复制到公共位置并提供它的链接(使用额外的机制,由cron运行,擦除公共图像目录时不时地为了不浪费空间,并robots.txt告诉谷歌不要索引目录).该解决方案将文件(每个给定时刻的一些文件)放在一个可公开访问的目录中(如果知道文件名),但也只需要一个视图助手,因此不启动引导程序:

class Zend_View_Helper_ShowImage extends Zend_View_Helper_Abstract {
    public function showImage ($filename) {
        if (!file_exists(PUBLIC_PATH."/img/{$filename}")) {
            if (!copy(PATH_TO_HIDDEN_FILES."/{$filename}",PUBLIC_PATH."/img/{$filename}"))
                $url = PUBLIC_PATH.'/img/nopicture.jpg';
            else
                $url = PUBLIC_PATH."/img/{$filename}";
        } else {
            $url = PUBLIC_PATH."/img/{$filename}"
        }
        return "{$url}";
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个助手的帮助下,视图中的调用非常简单:

<img src="<?php echo $this->showImage('filename.jpg'); ?>" />
Run Code Online (Sandbox Code Playgroud)

问题:正如我的同事所说,我的方法是否构成安全威胁?这有什么潜在的风险?而且,最重要的是,安全威胁(如果有的话)是否超过页面加载的10秒增益?

如果它很重要:我们正在建立一个拥有大约15,000注册用户的社区门户网站,其中的图库是一个非常常用的功能.

*我粘贴的代码是我们每个人提出的编辑简化版本 - 只是为了展示这两种方法的机制.

Ber*_*rak 6

我有一个不同的方法:我更喜欢将原始图像保存在隐藏位置,但是一旦请求它们,将它们复制到公共位置并提供指向它的链接

创意+1.

正如我的同事所说,我的方法是否会构成安全威胁?这有什么潜在的风险?而且,最重要的是,安全威胁(如果有的话)是否超过页面加载的10秒增益?

有点.是的,如果您有图像,只允许某些人看到,并且您将它们放入可公开访问的目录中,则会有其他人看到该图像的更改,这似乎是不合需要的.我也不认为(可能是错误的)它会在页面加载上获得10秒,因为你必须复制图像,这是一个相当密集的操作,而不是使用file_get_contents或readfile().

这是安全的,但由于我们使用Zend Framework,它也会慢速爬行 - 由于执行引导程序的查询,每次调用图像控制器都会花费大约500ms的延迟.

如果我可以建议; 这个具体案例的核心Zend框架.我也在使用Zend Framework作为一个相当大的网站,所以我知道引导程序可能比你想要的更长.如果你绕过Zend Framework,选择使用vanilla PHP,这将显着提高性能.

另外,使用readfile(),而不是file_get_contents().file_get_contents将在输出之前将整个文件加载到内存中,这有很大的不同,其中readfile可以更有效地执行此操作.

  • +1表示readfile.然而,有一个更好的解决方案 - fopen/fread/echo但是chunked.比方说,2kb块.性能比readfile好大约50%. (5认同)