`

表示不同文件类型的魔术数字

 
阅读更多

这里所说的表示不同文件类型的魔术数字,指的是文件的最开头的几个用于唯一区别其它文件类型的字节,有了这些魔术数字,我们就可以很方便的区别不同的文件,这也使得编程变得更加容易,因为我减少了我们用于区别一个文件的文件类型所要花费的时间。

比如,一个JPEG文件,它开头的一些字节可能是类似这样的”ffd8 ffe0 0010 4a46 4946 0001 0101 0047 ……JFIF…..G“,这里”ffd8“就表示了这个文件是一个JPEG类型的文件,”ffe0“表示这是JFIF类型结构。

以下例出的是一些我们常见的文件类型,以及它用于判断这种文件的类型的几个开始字节及所对尖的ASCII数字:

图片文件

文件类型 扩展名 16进制数字
xx这里表示变量 Ascii数字
. = 不是Ascii字符
Bitmap format .bmp 42 4d BM
FITS format .fits 53 49 4d 50 4c 45 SIMPLE
GIF format .gif 47 49 46 38 GIF8
Graphics Kernel System .gks 47 4b 53 4d GKSM
IRIS rgb format .rgb 01 da ..
ITC (CMU WM) format .itc f1 00 40 bb ….
JPEG File Interchange Format .jpg ff d8 ff e0 ….
NIFF (Navy TIFF) .nif 49 49 4e 31 IIN1
PM format .pm 56 49 45 57 VIEW
PNG format .png 89 50 4e 47 .PNG
Postscript format .[e]ps 25 21 %!
Sun Rasterfile .ras 59 a6 6a 95 Y.j.
Targa format .tga xx xx xx
TIFF format (Motorola – big endian) .tif 4d 4d 00 2a MM.*
TIFF format (Intel – little endian) .tif 49 49 2a 00 II*.
X11 Bitmap format .xbm xx xx  
XCF Gimp file structure .xcf 67 69 6d 70 20 78 63 66 20 76 gimp xcf
Xfig format .fig 23 46 49 47 #FIG
XPM format .xpm 2f 2a 20 58 50 4d 20 2a 2f /* XPM */

压缩文件

文件类型 扩展名 16进制数字
xx这里表示变量 Ascii数字
. = 不是Ascii字符
Bzip .bz 42 5a BZ
Compress .Z 1f 9d ..
gzip format .gz 1f 8b ..
pkzip format .zip 50 4b 03 04 PK..

存档文件

文件类型 扩展名 16进制数字
xx这里表示变量 Ascii数字
. = 不是Ascii字符
TAR (pre-POSIX) .tar xx xx (a filename)
TAR (POSIX) .tar 75 73 74 61 72 ustar (offset by 257 bytes)

可执行文件

文件类型 扩展名 16进制数字
xx这里表示变量 Ascii数字
. = 不是Ascii字符
MS-DOS, OS/2 or MS Windows   4d 5a MZ
Unix elf   7f 45 4c 46 .ELF

其它文件

 

 

文件类型 扩展名 16进制数字
xx这里表示变量 Ascii数字
. = 不是Ascii字符
pgp public ring   99 00 ..
pgp security ring   95 01 ..
pgp security ring   95 00 ..
pgp encrypted data   a6 00 ¦.

 

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

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

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

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

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

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

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

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

2. 伪造文件的Content-type,这个稍微复杂点,为了直观,截图如下:

 

 

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

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

 

                                                      被伪装成gif的恶意图片文件

对应的Java代码如下:

 

[java] view plain copy
 
 
 
 
  1. package apistudy;    
  2.     
  3. import java.awt.image.BufferedImage;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileNotFoundException;  
  7. import java.io.IOException;  
  8. import java.io.InputStream;  
  9. import java.util.HashMap;  
  10. import java.util.Iterator;  
  11. import java.util.Map;  
  12. import java.util.Map.Entry;  
  13. import javax.imageio.ImageIO;  
  14. import javax.imageio.ImageReader;  
  15. import javax.imageio.stream.ImageInputStream;  
  16.     
  17. public class FileTypeTest    
  18. {    
  19.     public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();    
  20.         
  21.     private FileTypeTest(){}    
  22.     static{    
  23.         getAllFileType();  //初始化文件类型信息    
  24.     }    
  25.         
  26.     /**  
  27.      * Created on 2010-7-1   
  28.      * <p>Discription:[getAllFileType,常见文件头信息]</p>  
  29.      * @author:[shixing_11@sina.com]  
  30.      */    
  31.     private static void getAllFileType()    
  32.     {    
  33.         FILE_TYPE_MAP.put("jpg""FFD8FF"); //JPEG (jpg)    
  34.         FILE_TYPE_MAP.put("png""89504E47");  //PNG (png)    
  35.         FILE_TYPE_MAP.put("gif""47494638");  //GIF (gif)    
  36.         FILE_TYPE_MAP.put("tif""49492A00");  //TIFF (tif)    
  37.         FILE_TYPE_MAP.put("bmp""424D"); //Windows Bitmap (bmp)    
  38.         FILE_TYPE_MAP.put("dwg""41433130"); //CAD (dwg)    
  39.         FILE_TYPE_MAP.put("html""68746D6C3E");  //HTML (html)    
  40.         FILE_TYPE_MAP.put("rtf""7B5C727466");  //Rich Text Format (rtf)    
  41.         FILE_TYPE_MAP.put("xml""3C3F786D6C");    
  42.         FILE_TYPE_MAP.put("zip""504B0304");    
  43.         FILE_TYPE_MAP.put("rar""52617221");    
  44.         FILE_TYPE_MAP.put("psd""38425053");  //Photoshop (psd)    
  45.         FILE_TYPE_MAP.put("eml""44656C69766572792D646174653A");  //Email [thorough only] (eml)    
  46.         FILE_TYPE_MAP.put("dbx""CFAD12FEC5FD746F");  //Outlook Express (dbx)    
  47.         FILE_TYPE_MAP.put("pst""2142444E");  //Outlook (pst)    
  48.         FILE_TYPE_MAP.put("xls""D0CF11E0");  //MS Word    
  49.         FILE_TYPE_MAP.put("doc""D0CF11E0");  //MS Excel 注意:word 和 excel的文件头一样    
  50.         FILE_TYPE_MAP.put("mdb""5374616E64617264204A");  //MS Access (mdb)    
  51.         FILE_TYPE_MAP.put("wpd""FF575043"); //WordPerfect (wpd)     
  52.         FILE_TYPE_MAP.put("eps""252150532D41646F6265");    
  53.         FILE_TYPE_MAP.put("ps""252150532D41646F6265");    
  54.         FILE_TYPE_MAP.put("pdf""255044462D312E");  //Adobe Acrobat (pdf)    
  55.         FILE_TYPE_MAP.put("qdf""AC9EBD8F");  //Quicken (qdf)    
  56.         FILE_TYPE_MAP.put("pwl""E3828596");  //Windows Password (pwl)    
  57.         FILE_TYPE_MAP.put("wav""57415645");  //Wave (wav)    
  58.         FILE_TYPE_MAP.put("avi""41564920");    
  59.         FILE_TYPE_MAP.put("ram""2E7261FD");  //Real Audio (ram)    
  60.         FILE_TYPE_MAP.put("rm""2E524D46");  //Real Media (rm)    
  61.         FILE_TYPE_MAP.put("mpg""000001BA");  //    
  62.         FILE_TYPE_MAP.put("mov""6D6F6F76");  //Quicktime (mov)    
  63.         FILE_TYPE_MAP.put("asf""3026B2758E66CF11"); //Windows Media (asf)    
  64.         FILE_TYPE_MAP.put("mid""4D546864");  //MIDI (mid)    
  65.     }    
  66.     
  67.     public static void main(String[] args) throws Exception    
  68.     {    
  69.         File f = new File("c://aaa.gif");    
  70.         if (f.exists())    
  71.         {    
  72.             String filetype1 = getImageFileType(f);    
  73.             System.out.println(filetype1);    
  74.             String filetype2 = getFileByFile(f);    
  75.             System.out.println(filetype2);    
  76.         }    
  77.     }    
  78.     
  79.     /**  
  80.      * Created on 2010-7-1   
  81.      * <p>Discription:[getImageFileType,获取图片文件实际类型,若不是图片则返回null]</p>  
  82.      * @param File  
  83.      * @return fileType  
  84.      * @author:[shixing_11@sina.com]  
  85.      */    
  86.     public final static String getImageFileType(File f)    
  87.     {    
  88.         if (isImage(f))  
  89.         {  
  90.             try  
  91.             {  
  92.                 ImageInputStream iis = ImageIO.createImageInputStream(f);  
  93.                 Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);  
  94.                 if (!iter.hasNext())  
  95.                 {  
  96.                     return null;  
  97.                 }  
  98.                 ImageReader reader = iter.next();  
  99.                 iis.close();  
  100.                 return reader.getFormatName();  
  101.             }  
  102.             catch (IOException e)  
  103.             {  
  104.                 return null;  
  105.             }  
  106.             catch (Exception e)  
  107.             {  
  108.                 return null;  
  109.             }  
  110.         }  
  111.         return null;  
  112.     }    
  113.     
  114.     /**  
  115.      * Created on 2010-7-1   
  116.      * <p>Discription:[getFileByFile,获取文件类型,包括图片,若格式不是已配置的,则返回null]</p>  
  117.      * @param file  
  118.      * @return fileType  
  119.      * @author:[shixing_11@sina.com]  
  120.      */    
  121.     public final static String getFileByFile(File file)    
  122.     {    
  123.         String filetype = null;    
  124.         byte[] b = new byte[50];    
  125.         try    
  126.         {    
  127.             InputStream is = new FileInputStream(file);    
  128.             is.read(b);    
  129.             filetype = getFileTypeByStream(b);    
  130.             is.close();    
  131.         }    
  132.         catch (FileNotFoundException e)    
  133.         {    
  134.             e.printStackTrace();    
  135.         }    
  136.         catch (IOException e)    
  137.         {    
  138.             e.printStackTrace();    
  139.         }    
  140.         return filetype;    
  141.     }    
  142.         
  143.     /**  
  144.      * Created on 2010-7-1   
  145.      * <p>Discription:[getFileTypeByStream]</p>  
  146.      * @param b  
  147.      * @return fileType  
  148.      * @author:[shixing_11@sina.com]  
  149.      */    
  150.     public final static String getFileTypeByStream(byte[] b)    
  151.     {    
  152.         String filetypeHex = String.valueOf(getFileHexString(b));    
  153.         Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();    
  154.         while (entryiterator.hasNext()) {    
  155.             Entry<String,String> entry =  entryiterator.next();    
  156.             String fileTypeHexValue = entry.getValue();    
  157.             if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {    
  158.                 return entry.getKey();    
  159.             }    
  160.         }    
  161.         return null;    
  162.     }    
  163.         
  164.     /** 
  165.      * Created on 2010-7-2  
  166.      * <p>Discription:[isImage,判断文件是否为图片]</p> 
  167.      * @param file 
  168.      * @return true 是 | false 否 
  169.      * @author:[shixing_11@sina.com] 
  170.      */  
  171.     public static final boolean isImage(File file){  
  172.         boolean flag = false;  
  173.         try  
  174.         {  
  175.             BufferedImage bufreader = ImageIO.read(file);  
  176.             int width = bufreader.getWidth();  
  177.             int height = bufreader.getHeight();  
  178.             if(width==0 || height==0){  
  179.                 flag = false;  
  180.             }else {  
  181.                 flag = true;  
  182.             }  
  183.         }  
  184.         catch (IOException e)  
  185.         {  
  186.             flag = false;  
  187.         }catch (Exception e) {  
  188.             flag = false;  
  189.         }  
  190.         return flag;  
  191.     }  
  192.       
  193.     /**  
  194.      * Created on 2010-7-1   
  195.      * <p>Discription:[getFileHexString]</p>  
  196.      * @param b  
  197.      * @return fileTypeHex  
  198.      * @author:[shixing_11@sina.com]  
  199.      */    
  200.     public final static String getFileHexString(byte[] b)    
  201.     {    
  202.         StringBuilder stringBuilder = new StringBuilder();    
  203.         if (b == null || b.length <= 0)    
  204.         {    
  205.             return null;    
  206.         }    
  207.         for (int i = 0; i < b.length; i++)    
  208.         {    
  209.             int v = b[i] & 0xFF;    
  210.             String hv = Integer.toHexString(v);    
  211.             if (hv.length() < 2)    
  212.             {    
  213.                 stringBuilder.append(0);    
  214.             }    
  215.             stringBuilder.append(hv);    
  216.         }    
  217.         return stringBuilder.toString();    
  218.     }    
  219. }  

  

这样,不管是传入的文件有后缀名,还是无后缀名,或者修改了后缀名,真正获取到的才是该文件的实际类型,这样避免了一些想通过修改后缀名或者Content-type信息来攻击的因素。但是性能与安全永远是无法同时完美的,安全的同时付出了读取文件的代价。本人建议可采用后缀名与读取文件的方式结合校验,毕竟攻击是少数,后缀名的校验能排除大多数用户,在后缀名获取不到时再通过获取文件真实类型校验,这样来适当提高性能。

分享到:
评论

相关推荐

    根据头信息判断文件类型

    根据头信息判断文件类型是计算机科学中的一个常见技术,它基于这样一个事实:大多数文件格式在开始部分都会包含一些特定的字节序列,这些序列被称为“魔术数字”或“文件签名”,用于标识文件的类型。这种方法在很多...

    arm elf文件格式简单分析

    ELF文件开始处有固定的标识符,即`e_ident`字段,它包括了文件的魔术数字和版本信息。例如,`EI_MAG0`至`EI_MAG3`分别对应于ELF文件头的前四个字节,其值应为`0x7f`, `'E'`, `'L'`, 和`'F'`,这是识别一个文件是否为...

    魔术数字游戏

    1. **基本数据类型与变量**:游戏可能会使用整型(int)来存储数字,浮点型(float或double)处理分数,布尔型(bool)表示条件状态等。 2. **流程控制**:通过if-else语句、switch-case结构来实现游戏逻辑判断,...

    Linux文件系统.pdf

    - Magic Number:魔术数字是一种用于识别文件类型的技术。Linux内核可以通过魔术数字快速识别文件系统类型。 - Revision Level:修订级别是指定文件系统版本的信息。 - Mount:挂载指的是将一个文件系统加入到系统...

    PE文件结构与ELF文件结构

    // 魔术数字 WORD e_cblp; // 文件最后页的字节数 WORD e_cp; // 文件页数 WORD e_crlc; // 重定义元素个数 WORD e_cparhdr; // 头部尺寸,以段落为单位 WORD e_minalloc; // 所需的最小附加段 WORD e_...

    winhex 查看文件的二进制十六进制

    通过查看十六进制,我们可以识别出特定的文件签名或魔术数字,这些是识别文件类型的关键。例如,JPEG图像的文件头通常以“FF D8 FF E0”开始,而PE(Portable Executable)可执行文件的头两个字节是“4D 5A”。 2. ...

    了解pcap文件格式

    - **链路层类型(LinkType)**: 根据不同的链路层协议有不同的值,例如Ethernet对应的值为1。 ##### 2. 数据包头部(PacketHeader) 每个数据包之前都有一个16字节的头部,用以描述该数据包的相关信息: ```c ...

    MNIST手写数字数据集

    - **图像文件(idx3-ubyte)**:以二进制格式存储,前16个字节是元数据,包括魔术数字(用于识别文件类型)、图像数量、宽度、高度和颜色通道数。MNIST中的图像为单通道(灰度),所以颜色通道数为1。接下来的数据...

    TI DSP COFF COM 详细说明

    - 魔术数(Magic Number):用来标识文件类型; - 机器类型(Machine Type):指定目标机器架构; - 节表项数(Number Of Sections):指明文件中有多少个节; - 时间戳(Time Date Stamp):记录文件创建的时间戳;...

    JavaClass文件的结构分析及其校验.pdf

    // 魔术数字,标识文件类型 u2 minor_version; // 次版本号 u2 major_version; // 主版本号 u2 constant_pool_count; // 常量池的元素数量 cp_info constant_pool[constant_pool_count - 1]; // 常量池 u2 ...

    cap或pcap文件

    // 魔术数字,用于识别文件格式,通常为0xA1B2C3D4 unsigned short version_major;// 主版本号,如0x02 unsigned short version_minor;// 次版本号,如0x04 int thiszone; // GMT到本地时间的校正值,一般设为0 ...

    PE文件结构详解

    // 魔术数字,通常为“MZ” USHORT e_cblp; // 文件最后一页的字节数 USHORT e_cp; // 文件页数 USHORT e_crlc; // 重定位元素个数 USHORT e_cparhdr; // 头部尺寸,以段落为单位 USHORT e_minalloc; // 所需...

    So文件抽取及加载器实现

    - **魔术数**:文件头部分的魔法数字用于标识文件类型,这里使用`"MELF"`作为标志。 - **文件大小与内存大小**:`e_filesz`表示文件实际大小,而`e_memsz`则表示包含bss段在内的文件在内存中的总大小。 - **动态段...

    linux的elf手册

    - `e_type`: 文件类型,如可执行文件、目标文件等。 - `e_machine`: 目标机器架构,如`EM_X86_64`表示x86_64架构。 - `e_version`: 文件版本。 - `e_entry`: 程序入口地址。 - `e_phoff`: 程序头表相对于文件...

    从cap或pcap文件结构到视频会议基础知识

    - **魔术数字**:通常为16进制的`0xa1b2c3d4`,用于确认文件格式。 - **版本号**:默认为主版本号`0x02`和次版本号`0x04`。 - **GMT到本地时间校正**:此字段未使用,一般设为0。 - **时间戳精度**:此字段也未使用...

    PHP中类型转换 ,常量,系统常量,魔术常量的详解

    在字符串拼接操作中,不同类型的值会被转换为字符串,如`NULL`会变成空字符串,布尔值`true`会转换为字符串`'1'`,`false`转换为空字符串。 - **强制类型转换**:可以使用类型转换函数如`intval`、`strval`和`...

    DOS软件EXE2BIN的C源程序代码

    在源代码中,程序员通常会使用结构体来表示DOS头,包括魔术数字(识别文件类型的标识),程序的起始地址,代码和数据段的大小等。例如: ```c struct dos_header { unsigned char magic; // 魔术数字,通常是'NE' ...

    MNIST的数据

    解压后,文件分为四部分:32位的魔术数字标识文件类型,32位的图像数量,32位的行数(28),和32位的列数(28)。接着是每个像素的值,是0到255之间的整数,表示灰度级别。 2. `train-labels-idx1-ubyte.gz`:这是...

    php通过文件头判断格式的方法

    这些序列称为魔术数字或文件签名。例如,一个PNG图片文件的头两个字节通常是0x89 0x50(在十进制中是137 80),它们被用来唯一地识别PNG文件。 在PHP中,我们可以使用标准的文件处理函数来读取文件的头部信息。具体...

    pcapng格式解析中文版

    - **文件头块**:定义了文件的基本属性,如魔术数字、主要版本号、次要版本号等。 - **接口描述块**:描述捕获数据的接口信息,包括接口ID、接口类型等。 - **简单包块**:包含了捕获到的数据包的信息,包括时间戳、...

Global site tag (gtag.js) - Google Analytics