40

我工作的公司最近在我们托管的网站上遭受了许多标头注入和文件上传漏洞的打击,虽然我们已经解决了有关标头注入攻击的问题,但我们尚未控制上传漏洞。

我正在尝试设置一个即插即用型上传脚本系列以供内部使用,设计师可以将其复制到他们网站的结构中,修改一些变量,并在其上准备好上传表单他们的网站。我们希望尽可能地限制我们的暴露(我们已经关闭了 fopen 和 shell 命令)。

我在过去一个小时内搜索了该站点,发现许多不同的答案涉及依赖外部资源的特定方法。你们都认为什么是最好的纯脚本解决方案,它足够具体,可以用作可靠的保护方法?另外,如果可能的话,我想将语言限制为 PHP 或伪代码。

编辑:我找到了我的答案(发布在下面),虽然它确实使用了 shell 命令 exec(),但如果你阻止上传脚本文件(这个解决方案做得很好),你不会遇到任何问题。

4

3 回答 3

77
  1. 只允许授权用户上传文件。您也可以添加验证码来阻止原始机器人。

  2. 首先,MAX_FILE_SIZE您的上传表单中设置 ,并在服务器上设置最大文件sizecount

    ini_set('post_max_size', '40M'); //or bigger by multiple files
    ini_set('upload_max_filesize', '40M');
    ini_set('max_file_uploads', 10);
    

    通过上传的文件进行大小检查:

    if ($fileInput['size'] > $sizeLimit)
        ; //handle size error here
    
  3. 您应该使用$_FILESandmove_uploaded_file()将您上传的文件放入正确的目录,或者如果您想处理它,请使用is_uploaded_file(). (这些函数的存在是为了防止由 .引起的文件名注入register_globals。)

    $uploadStoragePath = '/file_storage';
    $fileInput = $_FILES['image'];
    
    if ($fileInput['error'] != UPLOAD_ERR_OK)
        ; //handle upload error here, see http://php.net/manual/en/features.file-upload.errors.php
    
    //size check here
    
    $temporaryName = $fileInput['tmp_name'];
    $extension = pathinfo($fileInput['name'], PATHINFO_EXTENSION);
    
    //mime check, chmod, etc. here
    
    $name = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); //true random id
    
    move_uploaded_file($temporaryName, $uploadStoragePath.'/'.$name.'.'.$extension);
    

    始终生成随机 id 而不是使用原始文件名

  4. 为上传的文件创建一个新的子域,例如http://static.example.com或至少在 , 之外的一个新目录。public_html子域或目录不应执行任何文件。将其设置在服务器配置中,或通过目录设置.htaccess文件中。

        SetHandler none
        SetHandler default-handler
        Options -ExecCGI
        php_flag engine off
    

    设置它chmod()好。

        $noExecMode = 0644;
        chmod($uploadedFile, $noExecMode);
    

    也用于chmod()新上传的文件并将其设置在目录中。

  5. 您应该检查黑客发送的mime 类型。您应该创建一个允许的mime 类型的白名单。仅在不需要任何其他格式时才允许使用图像。任何其他格式都是安全威胁。图像也是如此,但至少我们有工具来处理它们……例如:图像文件中的 HTML可能会导致具有内容嗅探漏洞的浏览器导致XSS。当损坏的内容是PHP代码时,它可以与eval 注入漏洞结合使用。

    $userContent = '../uploads/malicious.jpg';
    include('includes/'.$userContent);
    

    尽量避免这种情况,例如使用 aclass autoloader而不是手动包含 php 文件...
    通过首先处理javascript 注入,您必须关闭浏览器中的xss内容嗅探内容嗅探问题是较旧的msie的典型问题,我认为其他浏览器可以很好地过滤它们。无论如何,您可以使用一堆标题来防止这些问题。(并非每个浏览器都完全支持,但这是您在客户端可以做的最好的事情。)

    Strict-Transport-Security: max-age={your-max-age}
    X-Content-Type-Options: nosniff
    X-Frame-Options: deny
    X-XSS-Protection: 1; mode=block
    Content-Security-Policy: {your-security-policy}
    

    您可以使用 来检查文件是否损坏Imagick identify,但这并不意味着完全保护。

    try {
        $uploadedImage = new Imagick($uploadedFile);
        $attributes = $uploadedImage->identifyImage();
        $format = $image->getImageFormat();
        var_dump($attributes, $format);
    } catch (ImagickException $exception) {
        //handle damaged or corrupted images
    }
    

    如果你想为其他mime 类型提供服务,你应该总是强制他们下载,永远不要它们包含到网页中,除非你真的知道你在做什么......

    X-Download-Options: noopen
    Content-Disposition: attachment; filename=untrustedfile.html
    
  6. 可以有有效的图像文件,其中包含代码,例如在exif数据中。所以你必须从 images中清除exif,如果它的内容对你不重要。您可以使用Imagickor来做到这一点GD,但它们都需要重新打包文件。您可以找到exiftool一个替代方案。我认为清除exif的最简单方法是使用GD加载图像,并将它们保存为最高质量的PNG。所以图像不会损失质量,exif标签会被清除,因为GD无法处理它。也可以使用上传为PNG的图像来制作它...
    如果要提取exif数据,切勿使用preg_replace()if patternorreplacement来自用户,因为这将导致eval 注入...如有必要,请使用preg_replace_callback()而不是。eval regex flag(复制粘贴代码中的常见错误。) 如果您的网站存在eval 注入漏洞,例如,如果您在某处使用,则Exif数据可能会成为问题。include($userInput)

  7. include()require()如果您想控制访问,永远不要使用,通过上传文件,将它们作为静态或使用file_get_contents()or或任何其他文件读取功能。 它很少可用,但我认为将标头与sendfile apache 模块一起使用的最佳方法。通过标头,切勿使用未经验证或清理的用户输入,因为这将导致HTTP 标头注入。 如果您不需要访问控制(意味着:只有授权用户可以看到上传的文件),则使用您的网络服务器提供文件。它要快得多...readfile()
    X-Sendfile: {filename}

  8. 使用杀毒软件检查上传的文件(如果有的话)。

  9. Always use a combined protection, not just a single approach. It will be harder to breach your defenses...

于 2013-08-30T10:42:33.517 回答
39

恕我直言,最好的解决方案是将包含上传文件的目录放在“网络”环境之外,并使用脚本使它们可下载。这样,即使有人上传了脚本,也无法通过浏览器调用来执行,也不必检查上传文件的类型。

于 2008-11-01T23:53:04.530 回答
1

使用和配置Hardened-PHP使用move_uploaded_file$_FILES superglobal创建一个纯脚本。脚本越简单,就越安全(至少,与正在运行的 PHP 版本本身一样安全)

于 2008-11-01T22:59:52.140 回答