记一个漏洞处理,SSH框架上传限制文件类型,以及关于文件上传安全问题的讨论

发布时间 2023-11-17 17:04:10作者: dirgo

-----------------------------------------------------------------------------------------------------------------------------------

与同事讨论的文件上传安全问题:

1.老项目采用的上传至项目下某个目录的做法是很不安全的,容易被访问到上传文件,应当制定到项目之外的目录.

2.如果只使用一次,比如上传Excel导入数据,则可以不将文件保存到磁盘.

3.限制文件类型使用 后缀名 判断即可,因为只要黑客可以操作修改后缀名了,那改文件头之类的也可以被改回.

4.条件允许的话使用 minio存储系统,设置token 和有效时间,可增强安全性

5.新型的攻击方式改为攻击防护薄弱的客户端

----------------------------------------------------------------------------------------------------------------------------------------------------------

背景:公司老项目,使用的一个基于SSH的老框架二次开发,原框架封装的上传类没有限制文件类型,等保评测查出需要整改

思路:因为原上传类封装在jar包中不好处理,所以在web.xml中将处理上传的类改为自己编写的类

即:

<servlet>
        <servlet-name>fileUpload</servlet-name>
        <!-- <servlet-class>com.htsoft.core.web.servlet.FileUploadServlet</servlet-class> -->
        <!-- 替换htsoft封装的原有上传方法,加入对文件类型的过滤,只允许上传几种文件,防止恶意上传可执行文件 -->
        <servlet-class>com.htsoft.core.web.servlet.FileUploadServletNew</servlet-class>
    </servlet>

上传处理类

public class FileUploadServletNew extends HttpServlet{
 
    private static final long serialVersionUID = 1L;

    private Log logger=LogFactory.getLog(FileUploadServletNew.class);
    
    @SuppressWarnings("unused")
    private ServletConfig servletConfig=null;
    
    private FileAttachService fileAttachService=(FileAttachService)AppUtil.getBean("fileAttachService");

    private AppUserService appUserService = (AppUserService)AppUtil.getBean("appUserService");
    
    private GlobalTypeService globalTypeService = (GlobalTypeService)AppUtil.getBean("globalTypeService");
    
    private String uploadPath=""; // 上传文件的目录   
    private String tempPath=""; // 临时文件目录 
    
    private String fileCat="others";
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("===========上传方法New===========");
        String flexUserId = req.getParameter("flexUserId"); // flex中获取登录用户的id
        String fileTypeId = req.getParameter("fileTypeId"); // 附件类型id
        GlobalType globalType = null;
        if(StringUtils.isNotEmpty(fileTypeId)){
            globalType = globalTypeService.get(new Long(fileTypeId));
        }
        //指定保存至某个目录,若提交时,指定了该参数值,则表示保存的操作 
        String filePath="";
        String fileId="";
        
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        try {
            
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 缓存大小
            factory.setSizeThreshold(4096);
            factory.setRepository(new File(tempPath));
            ServletFileUpload fu=new ServletFileUpload(factory);

            List<FileItem> fileItems = fu.parseRequest(req); 
            //取得相关参数值
            for(FileItem fi:fileItems){
                if("file_cat".equals(fi.getFieldName())){
                    fileCat=fi.getString();
                    //break;
                }
                if("file_path".equals(fi.getFieldName())){
                    filePath=fi.getString();
                }
                if("fileId".equals(fi.getFieldName())){
                    fileId=fi.getString();
                }
            }
            logger.info("fileId:" + fileId);
            Iterator<FileItem> i = fileItems.iterator();
            StringBuffer sb = new StringBuffer("");
            StringBuffer sb1 = new StringBuffer("");
            StringBuffer sb2 = new StringBuffer("");
            
            sb = new StringBuffer("{\"success\":\"true\"");
            sb.append(",\"fileId\":[");
            
            //目前处理每次只上传一个文件
            while(i.hasNext()) {
                FileAttach file=null;
                FileItem fi = (FileItem)i.next();
            
                if(fi.getContentType()==null){
                    continue;
                }
                
                //返回文件名及路径及fileId.
                String path = fi.getName();
                
                int start=path.lastIndexOf("\\");
                
                //原文件名
                String fileName=path.substring(start+1);
                
              //处理文件名,只允许xls,xlxs
                int hzmindex=fileName.lastIndexOf(".");
                String hzm = fileName.substring(hzmindex+1);
                if(!(hzm.equals("xls") || hzm.equals("xlsx"))){
                    System.out.println("=======文件类型错误,只允许上传Excel文件!========");
                    sb2.append("文件类型错误,只允许上传Excel文件!");
                    break;
                }
                
                
                String relativeFullPath=null;
                
                if(!"".equals(filePath)){
                    relativeFullPath=filePath;
                }
                else if(!"".equals(fileId)){
                  FileAttach fileAttach=fileAttachService.get(new Long(fileId));
                  relativeFullPath=fileAttach.getFilePath();
                  logger.info("exist filePath:" + relativeFullPath);
                }
                else{
                    relativeFullPath=fileCat+"/" + FileUtil.generateFilename(fileName);
                }
                
                int index=relativeFullPath.lastIndexOf("/");

                File dirPath=new File(uploadPath+"/" + relativeFullPath.substring(0,index+1));
                
                if(!dirPath.exists()){
                    dirPath.mkdirs();
                }

                fi.write(new File(uploadPath+"/" + relativeFullPath));
                
                if(!"".equals(filePath)){
                    file=fileAttachService.getByPath(filePath);
                    file.setTotalBytes(fi.getSize());
                    file.setNote(getStrFileSize(fi.getSize()));
                    fileAttachService.save(file);
                }
                if(!"".equals(fileId)){
                    file=fileAttachService.get(new Long(fileId));
                    file.setTotalBytes(fi.getSize());
                    file.setNote(getStrFileSize(fi.getSize()));
                    fileAttachService.save(file);
                }
                
                if(file==null) {
                    file=new FileAttach();
                    file.setCreatetime(new Date());
                    AppUser curUser = ContextUtil.getCurrentUser();
                    if(StringUtils.isNotEmpty("isFlex") && StringUtils.isNotEmpty(flexUserId)){
                        curUser = appUserService.get(new Long(flexUserId));
                    }
                    if(curUser != null){
                        file.setCreator(curUser.getFullname());
                        file.setCreatorId(curUser.getUserId());
                    } else {
                        file.setCreator("UNKown");
                    }
                    int dotIndex=fileName.lastIndexOf(".");
                    file.setExt(fileName.substring(dotIndex+1));
                    file.setFileName(fileName);
                    file.setFilePath(relativeFullPath);
                    file.setFileType(fileCat);
                    if(globalType == null){
                        globalType = globalTypeService.findByFileType(fileCat);
                    }  
                    if(globalType != null){                        
                        file.setGlobalType(globalType);
                    }
                    file.setTotalBytes(fi.getSize());
                    file.setNote(getStrFileSize(fi.getSize()));
                    file.setCreatorId(curUser.getUserId());
                    file.setDelFlag(FileAttach.FLAG_NOT_DEL);
                    FileAttach newFile = new FileAttach();
                    if(file.getTotalBytes()>0) {
                        //将文件信息存入数据库
                        newFile = fileAttachService.save(file);
                    }
                  //组建返回文件信息的json字符串
                    sb1.append(newFile.getFileId()+",");
                }
                
            }
            
            if(sb2.toString().equals("")){
            String str = sb1.substring(0, sb1.length()-1);
            if(str!=null&&(!str.equals("null"))&&str.length()>0) {
                sb.append(str);
            }
            sb.append("]}");
            }else{
                System.out.println("=======出错========");
                sb = new StringBuffer("{'success':false,'message':'"+sb2.toString()+"'}");
            }
            
            
            resp.setContentType("text/html;charset=UTF-8");
            PrintWriter writer = resp.getWriter();
            
            writer.println(sb.toString());
        }    
        catch(Exception e) {    
            resp.getWriter().write("{'success':false,'message':'error..."+e.getMessage()+"'}");
        }    
        
    }
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        this.servletConfig=config;
    }
    
    public void init() throws ServletException {
       
        //初始化上传的路径及临时文件路径
        
        uploadPath=getServletContext().getRealPath("/attachFiles/");
        
        File uploadPathFile=new File(uploadPath);
        if(!uploadPathFile.exists()){
            uploadPathFile.mkdirs();
        }
        tempPath=uploadPath+"/temp";
        
        File tempPathFile=new File(tempPath); 
        if(!tempPathFile.exists()){
            tempPathFile.mkdirs();
        }
    }
    
    
    /*------------------------------------------------------------
    保存文档到服务器磁盘,返回值true,保存成功,返回值为false时,保存失败。
    --------------------------------------------------------------*/
    @SuppressWarnings("unused")
    public boolean saveFileToDisk(String officefileNameDisk)
    {
        File officeFileUpload = null;
        FileItem officeFileItem =null ;
        
        boolean result=true ;
        try
        {
            if(!"".equalsIgnoreCase(officefileNameDisk)&&officeFileItem!=null)
            {
                officeFileUpload =  new File(uploadPath+officefileNameDisk);
                officeFileItem.write(officeFileUpload);
            }
        }catch(FileNotFoundException e){
            
        }catch(Exception e){
            e.printStackTrace();
            result=false;
        }
        return result;    
    }
    
    private String getStrFileSize(double size){
        DecimalFormat df=new DecimalFormat("0.00");
        if(size>1024*1024){
             double ss=size/(1024*1024);
              return df.format(ss)+" M";
        }else if(size>1024){
            double ss=size/1024;
            return df.format(ss)+" KB";
        }else{
            return size+" bytes";
        }
    }

    
}