JAVA对文件类型的校验

通常,在WEB系统中,上传文件时都需要做文件的类型校验,大致有如下几种方法:

1. 通过后缀名,如exe,jpg,bmp,rar,zip等等。

2. 通过读取文件,获取文件的Content-type来判断。

3. 通过读取文件流,根据文件流中特定的一些字节标识来区分不同类型的文件。

4. 若是图片,则通过缩放来判断,可以缩放的为图片,不可以的则不是。

然而,在安全性较高的业务场景中,1,2两种方法的校验会被轻易绕过。

1. 伪造后缀名,如图片的,非常容易修改。

2. 伪造文件的Content-type,这个稍微复杂点,

3.较安全,但是要读取文件,并有16进制转换等操作,性能稍差,但能满足一定条件下对安全的要求,所以建议使用。

但是文件头的信息也可以伪造,截图如下,对于图片可以采用图片缩放或者获取图片宽高的方法避免伪造头信息漏洞。

 

[java] view plain copy
 
  1. package com.nfschina.utils.file;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.util.HashMap;  
  6. import java.util.Iterator;  
  7. import java.util.Map;  
  8. import java.util.Map.Entry;  
  9.   
  10. import com.nfschina.utils.BaseException;  
  11.   
  12. /*********************************************************************** 
  13.  * 
  14.  * Description: 主要用于判断文件的类型 
  15.  * 
  16.  ***********************************************************************/  
  17.   
  18. public class FileTools {  
  19.    
  20.  public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();              
  21.       
  22.  /*-----------------------------目前可以识别的类型----------------------------*/  
  23.     private static void getAllFileType()       
  24.     {       
  25.         FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG        
  26.         FILE_TYPE_MAP.put("png", "89504E47"); //PNG        
  27.         FILE_TYPE_MAP.put("gif", "47494638"); //GIF       
  28.         FILE_TYPE_MAP.put("tif", "49492A00"); //TIFF      
  29.         FILE_TYPE_MAP.put("bmp", "424D"); //Windows Bitmap       
  30.         FILE_TYPE_MAP.put("dwg", "41433130"); //CAD     
  31.         FILE_TYPE_MAP.put("html", "68746D6C3E"); //HTML      
  32.         FILE_TYPE_MAP.put("rtf", "7B5C727466"); //Rich Text Format      
  33.         FILE_TYPE_MAP.put("xml", "3C3F786D6C");       
  34.         FILE_TYPE_MAP.put("zip", "504B0304");       
  35.         FILE_TYPE_MAP.put("rar", "52617221");       
  36.         FILE_TYPE_MAP.put("psd", "38425053"); //PhotoShop    
  37.         FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A"); //Email [thorough only]     
  38.         FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F"); //Outlook Express     
  39.         FILE_TYPE_MAP.put("pst", "2142444E"); //Outlook        
  40.         FILE_TYPE_MAP.put("office", "D0CF11E0"); //office类型,包括doc、xls和ppt       
  41.         FILE_TYPE_MAP.put("mdb", "000100005374616E64617264204A"); //MS Access       
  42.         FILE_TYPE_MAP.put("wpd", "FF575043"); //WordPerfect     
  43.         FILE_TYPE_MAP.put("eps", "252150532D41646F6265");       
  44.         FILE_TYPE_MAP.put("ps", "252150532D41646F6265");       
  45.         FILE_TYPE_MAP.put("pdf", "255044462D312E"); //Adobe Acrobat     
  46.         FILE_TYPE_MAP.put("qdf", "AC9EBD8F"); //Quicken    
  47.         FILE_TYPE_MAP.put("pwl", "E3828596"); //Windows Password   
  48.         FILE_TYPE_MAP.put("wav", "57415645"); //Wave     
  49.         FILE_TYPE_MAP.put("avi", "41564920");       
  50.         FILE_TYPE_MAP.put("ram", "2E7261FD"); //Real Audio       
  51.         FILE_TYPE_MAP.put("rm", "2E524D46"); //Real Media       
  52.         FILE_TYPE_MAP.put("mpg", "000001BA"); //       
  53.         FILE_TYPE_MAP.put("mov", "6D6F6F76"); //Quicktime       
  54.         FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); //Windows Media      
  55.         FILE_TYPE_MAP.put("mid", "4D546864"); //MIDI (mid)       
  56.     }       
  57.    
  58.     /** 
  59.      * 通过读取文件头部获得文件类型 
  60.      * @param file 
  61.      * @return 文件类型 
  62.      * @throws BaseException 
  63.      */  
  64.  public static String getFileType(File file) throws BaseException{  
  65.   getAllFileType();  
  66.   String fileExtendName = null;  
  67.   FileInputStream is;  
  68.   try {  
  69.    is = new FileInputStream(file);  
  70.             byte[] b = new byte[16];    
  71.             is.read(b,0, b.length);    
  72.             String filetypeHex = String.valueOf(bytesToHexString(b));    
  73.             Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();   
  74.             while (entryiterator.hasNext()) {   
  75.                 Entry<String,String> entry = entryiterator.next();   
  76.                 String fileTypeHexValue = entry.getValue();   
  77.                 if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {   
  78.                  fileExtendName = entry.getKey();   
  79.                  if(fileExtendName.equals("office")) {  
  80.                   fileExtendName = getOfficeFileType(is);  
  81.                  }  
  82.                  is.close();  
  83.                  break;  
  84.                 }  
  85.             }  
  86.               
  87.             // 如果不是上述类型,则判断扩展名  
  88.             if(fileExtendName == null)  
  89.             {  
  90.              String fileName = file.getName();  
  91.              // 如果无扩展名,则直接返回空串  
  92.              if(-1 == fileName.indexOf("."))  
  93.              {  
  94.               return "";  
  95.              }  
  96.              // 如果有扩展名,则返回扩展名  
  97.              return fileName.substring(fileName.indexOf(".") + 1);  
  98.             }  
  99.             is.close();  
  100.       return fileExtendName;  
  101.   } catch (Exception exception) {  
  102.    throw new BaseException(exception.getMessage(), exception);  
  103.   }  
  104.  }  
  105.    
  106.  /** 
  107.   * 判断office文件的具体类型 
  108.   * @param fileInputStream 
  109.   * @return office文件具体类型 
  110.   * @throws BaseException 
  111.   */  
  112.   private static String getOfficeFileType(FileInputStream fileInputStream) throws BaseException{  
  113.    String officeFileType = "doc";  
  114.    byte[] b = new byte[512];    
  115.       try {  
  116.        fileInputStream.read(b, 0, b.length);  
  117.     String filetypeHex = String.valueOf(bytesToHexString(b));   
  118.        String flagString = filetypeHex.substring(992, filetypeHex.length());  
  119.        if(flagString.toLowerCase().startsWith("eca5c")){  
  120.         officeFileType = "doc";  
  121.        } else if(flagString.toLowerCase().startsWith("fdffffff09")){  
  122.         officeFileType = "xls";  
  123.           
  124.        } else if(flagString.toLowerCase().startsWith("09081000000")){  
  125.         officeFileType = "xls";  
  126.        } else {  
  127.         officeFileType = "ppt";  
  128.        }  
  129.     return officeFileType;  
  130.       } catch (Exception exception) {  
  131.        throw new BaseException(exception.getMessage(), exception);  
  132.    }   
  133.   }  
  134.     
  135.   /** 
  136.    * 获得文件头部字符串 
  137.    * @param src 
  138.    * @return 
  139.    */  
  140.  private static String bytesToHexString(byte[] src){       
  141.         StringBuilder stringBuilder = new StringBuilder();       
  142.         if (src == null || src.length <= 0) {       
  143.             return null;       
  144.         }       
  145.         for (int i = 0; i < src.length; i++) {       
  146.             int v = src[i] & 0xFF;    
  147.             String hv = Integer.toHexString(v);       
  148.             if (hv.length() < 2) {       
  149.                 stringBuilder.append(0);       
  150.             }       
  151.             stringBuilder.append(hv);       
  152.         }       
  153.         return stringBuilder.toString();       
  154.     }    
  155.    
  156.  public static void main(String[] args)  
  157.  {  
  158.     
  159.   File file = new File("E:/新闻公告.pdm");  
  160.   FileInputStream is;  
  161.   try{  
  162.    is = new FileInputStream(file);  
  163.             byte[] b = new byte[16];    
  164.             is.read(b,0, b.length);    
  165. //            String filetypeHex = String.valueOf(bytesToHexString(b));    
  166.             String fileName = file.getName();  
  167.             System.out.println(fileName.substring(fileName.indexOf(".") + 1));  
  168.   }catch(Exception e)  
  169.   {  
  170.    e.printStackTrace();  
  171.   }  
  172.     
  173.  }

 

posted @ 2016-09-26 09:11  DearBelinda  阅读(12144)  评论(0编辑  收藏  举报