如果人家想上传一个代码的TXT怎么办? 
可以让服务器不执行。txt文件,禁 止执行,或只允下载

解决方案 »

  1.   

    用虚拟目录是一个非常好的办法。但是这就对服务器配置有需求了。比如在虚拟空间上,就很难去配置一个无脚本执行的虚拟目录。
    而且如果用变量做路径
    webpath/upload/file/ssssss.jpg
    可能会被恶意欺骗上传后成为/webpath/virus.asp
    这样的问题很严重。
    由于c语言的char数组最后结尾\0这个个边界检查不严格导致的上传漏洞,很烦人。
    不知道有没有非常好的解决方法
      

  2.   

    楼上的别忘了可以构造路径
    那么就说明路径并不是安全的。这点解决方法就是路径作为常量,但是对于高级应用显然不够灵活。
    比如以前动网的那个上传漏洞
             uploadfiles/20080730/20080730173347.jpg
    那么按设置的话,就是uploadfiles为单独一个虚拟目录,引用方式为www.website.com/uploadfiles/
    但是当年那个漏洞构造了路径会传到网站根目录,也就是本来应该
     www.website.com/uploadfiles/20080730/20080730173347.jpg
    说传到了www.website.com/a.asp或者www.website.com/a.php
    很显然这种情况下绕过了路径,那么不执行的虚拟目录就形同虚设了。
      

  3.   


    汗...名字不错...以后开个菜馆可以做个这道菜...kaspersky有linux版的吗?
      

  4.   

    恩,后来的动网解决了这个问题,DISCUZ应该也解决了的。
      

  5.   

    自己写了一个,不知道这样会不会被伪造路径
    /*
      *类名:upload
      *说明:上传类
      *要求PHP>=5.0
      *相关说明:
      *$_FILES['userfile']['name']客户端机器文件的原名称。 
      *$_FILES['userfile']['type']文件的 MIME 类型,如果浏览器提供此信息的话。一个例子是“image/gif”。不过此 MIME 类型在 PHP 端并不检查,因此不要想当然认为有这个值。 
      *$_FILES['userfile']['size']已上传文件的大小,单位为字节。
      *$_FILES['userfile']['tmp_name']文件被上传后在服务端储存的临时文件名
      *$_FILES['userfile']['error']和该文件上传相关的错误代码。此项目是在 PHP 4.2.0 版本中增加的。  */

    class upload{

    //public 属性,从客户端$_FILES['userfile']获得
    public  $fileName=""; //文件名
    public  $errorNum;       //$_FILES['userfile']['error']错误
    public  $file_type=null;
    public  $tmpName=null; //在服务器上的临时文件,完整文件路径+文件名
    public  $file_Size=0;//文件大小 //私有属性

    private $errorMsg;
    private $uploadfileName=""; //上传后的文件名,带后缀
    private $extension=""; //后缀名
    private $allow_ext; //允许的扩展名
    private $max_file_size=200;// 最大允许文件大小
    private $upload_path="";//目录
    private $fileNameByDate = True;
    private $isImage=false; //是否是图片
    private $imgHeight=300; //图片高度
    private $imgWidth=300; //图片宽度
    //设置上传路径
    public function setUploadPath($path)
    {
    if (isset($path))
    {
    if(!is_dir($path)){die("上传目录不是一个有效的目录");}
    $this->upload_path = $path;
    }
    }
    /*设置上传文件类型限制
     *参数:array:ext
     */
    public function setAllowExt($ext)
    {
    if (isset($ext))
    { if(!is_array($ext)){die("类型参数必须为一个数组");}
    $this->allow_ext = $ext;
    } }

    /*设置上传文件大小(单位K)
     *参数:int:ext
     */
    public function setMaxFileSize($size)
    {
    if (isset($size))
    {
    if(!is_numeric($size)){die("文件大小设置必须为数字");}
    $this->max_file_size = $size * 1024;
    }
    } //设置图片文件高度宽度限制
    public function setImageWH($width,$height)
    {
    if(!is_numeric($width)){die("文件宽度设置必须为数字");}
    if(!is_numeric($height)){die("文件高度设置必须为数字");}
    $this->imgWidth = $width;
    $this->imgHeight = $height;
    }

     /**
     * 上传文件
     * @param string $newfilename  上传后的新文件名
     * @param bool $checkImageWH  是否检查图片的宽和高
     * @param bool $is_escape_html  是否允许上传的文件中带html,php标记
     * @return  bool
     * 用法举例:uploadfile("abc.jpg")
     */
    public function uploadfile($newfilename,$checkImageWH=false,$is_escape_html=true)
    {
    if(!$this->checkfile($checkImageWH))
    {

    return false;
    }

    $uploadfile = $this->upload_path.basename($newfilename).".".$this->extension; //上传后完整路径+文件名+后缀
    $this->uploadfileName = $uploadfile;
    if(@move_uploaded_file($this->tmpName,$uploadfile))
    {
    $this->errorNum=0;

    $this->check_file_safe($is_escape_html);
    return true;
    }


    return false;


    }

    /*综合检查上传文件
     *
     *
     */
    public function checkfile($checkImageWH = false)
    {

    if($this->errorNum !=0){return false;}
    if(!is_uploaded_file($this->tmpName)) {return false;} //检查是否是上传文件
    if(!$this->check_file_ext($this->fileName)) {return false;} //检查input本地文件后缀名
    if(!$this->check_file_size()){return false;} //检查文件大小
    if(!$this->check_is_image($this->tmpName)) {return false;} //伪造图片判断
    if($checkImageWH)
    {
    if(!$this->check_file_wh($this->tmpName)) {return false;}
    }

    return true;
    }
     /**
     * 检查文件后缀
     * @param string $filename  文件名字,字符串
     * @return  bool
     * 用法举例:check_file_ext("abc.jpg")
     */
    public function check_file_ext($filename)
    {
    $filename=strtolower($filename);
    $ext = substr(strrchr($filename,"."),1);
    $this->extension=$ext;  //赋值私有属性后缀名
    foreach ($this->allow_ext as $key =>$value )
    {
    if ($ext ==$this->allow_ext[$key]) {return true;}
    }
    $this->errorNum=5;
    return false;
    }

    //检查文件大小 public function check_file_size()
    {
    if($this->file_Size > $this->max_file_size*1024)
    {
    $this->errorNum=8;
    return false;
    }
    return true;
    }
    //检查是否伪造图片
    //索引 2 是图像类型的标记:1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM
    public function check_is_image($tmp_file)
    {
    if($this->file_type=="image/png" || $this->file_type=="image/jpeg" || $this->file_type=="image/gif")
    {
    $image= @getimagesize($tmp_file);
    if ($image[2] ==1 || $image[2] ==2 || $image[2] ==3) //mime类型与getimagesize判断一致,确实为图片
    {
    $this->isImage=true;
    return true;
    }
    else
    {
    $this->errorNum=5;
    $this->isImage=false;
    return false;
    }
    }

    return true;
    } //检查图片文件宽度高度
    //$filename为上传临时文件
    public function check_file_wh($filename)
    {
    $image= @getimagesize($filename);
    if($image[2] ==1 || $image[2] ==2 || $image[2] ==3 ) //为允许的图片格式
    {
    $this->isImage=true;
    if ($image[0]>$this->imgWidth){$this->errorNum=9;return false;}
    if ($image[1]>$this->imgHeight){$this->errorNum=10;return false;}
    return true;

    } $this->isImage=false;
    return true; //不是图片不检查
    }

        /**
     * 上传文件后安全检测
     * @param $is_escape_html=true 是否要过滤HTML标记
     * @return  bool
     * 用法举例:
     */
    public function check_file_safe($is_escape_html=true)
    {

    if (($is_escape_html)&&($this->file_type=="text/plain")&&(is_file($this->uploadfileName)))
    {
    $fp = @fopen($this->uploadfileName,"r");
    $contents = @fread($fp,filesize($this->uploadfileName));
    @fclose($fp);
    $contents = strip_tags($contents);
    $fp = @fopen($this->uploadfileName,"w");
    @fwrite($fp,$contents);
    @fclose($fp);
    }
    else
    {
    //todo扩展
     
    } }

    /**
     * 输出错误
     * @param string 
     * @return  
     * 用法举例:
     */

    public function outputMsg()
    {

    echo $this->errorMsg[$this->errorNum];
    //if ($this->errorNum==0) {echo "上传成功!";}

    } //构造函数
    function __construct(){
    $this->errorMsg[0] = "没有错误发生,文件上传成功";
    $this->errorMsg[1] = "上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值";
    $this->errorMsg[2] = "上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值";
    $this->errorMsg[3] = "文件只有部分被上传";
    $this->errorMsg[4] = "没有文件被上传";
    $this->errorMsg[5] = "不允许的文件类型";
    $this->errorMsg[6] = "找不到临时文件夹";
    $this->errorMsg[7] = "文件写入失败";
    $this->errorMsg[8] = "超过自定义文件大小".$this->max_file_size."K";
    $this->errorMsg[9] = "图片宽度超过预定义".$this->imgWidth;
    $this->errorMsg[10] = "图片高度超过预定义".$this->imgHeight;


    $this->allow_ext =Array("jpg","gif","jpeg","png","txt","rar","zip");

    $this->upload_path = $_SERVER["DOCUMENT_ROOT"]."/uploadfiles/"; //默认uploadfiles为上传目录 }  //析构函数
    function __destruct()
     {

     }

    }
      

  6.   

    我分析了动网以前的那个漏洞,路径被构造原因是路径保存在了hidden里,感觉如果服务端生成路径的话,应该不会有这个问题。而且PHP5先上传到临时目录在copy过去。
    其实构造文件名,我这里上传的话对图片格式做了特殊处理,判断高度宽度,没有宽度高度为构造的假文件,如果构造ZIP和RAR会直接下载,而不会运行。应该是算比较安全了。恩,对于IIS6还有一个特殊的上传漏洞,如果文件夹命名为1.asp,2.asp之类的名字,那么这个目录下的jpg和其他文件都会被作为ASP运行,刚测试,微软还没补丁貌似。这种情况,如果不用用户名做目录名,应该可以防止。差不多,配合权限设置,上传可以做到安全。
    大家还是什么补充,要结贴了
      

  7.   

    PHP本身没有上传安全问题吧 只是上传目录在可直接访问目录中可能导致 执行脚本最简单快捷的方法是设置个静态虚拟机 严禁执行任何脚本 所有静态内容都通过这个虚拟机访问 现在有很多img.xxx.com的实例
    租用空间的似乎不可以 但可以把上传目录放在不可以直接访问的目录中 通过 fopen fread echo 这样来输出