这里所说的表示不同文件类型的魔术数字,指的是文件的最开头的几个用于唯一区别其它文件类型的字节,有了这些魔术数字,我们就可以很方便的区别不同的文件,这也使得编程变得更加容易,因为我减少了我们用于区别一个文件的文件类型所要花费的时间。
比如,一个JPEG文件,它开头的一些字节可能是类似这样的”ffd8 ffe0 0010 4a46 4946 0001 0101 0047 ……JFIF…..G“,这里”ffd8“就表示了这个文件是一个JPEG类型的文件,”ffe0“表示这是JFIF类型结构。
以下例出的是一些我们常见的文件类型,以及它用于判断这种文件的类型的几个开始字节及所对尖的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 */ |
压缩文件
Bzip | .bz | 42 5a | BZ |
Compress | .Z | 1f 9d | .. |
gzip format | .gz | 1f 8b | .. |
pkzip format | .zip | 50 4b 03 04 | PK.. |
存档文件
TAR (pre-POSIX) | .tar | xx xx | (a filename) |
TAR (POSIX) | .tar | 75 73 74 61 72 | ustar (offset by 257 bytes) |
可执行文件
MS-DOS, OS/2 or MS Windows | 4d 5a | MZ | |
Unix elf | 7f 45 4c 46 | .ELF |
其它文件
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代码如下:
- package apistudy;
- import java.awt.image.BufferedImage;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Map.Entry;
- import javax.imageio.ImageIO;
- import javax.imageio.ImageReader;
- import javax.imageio.stream.ImageInputStream;
- public class FileTypeTest
- {
- public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();
- private FileTypeTest(){}
- static{
- getAllFileType(); //初始化文件类型信息
- }
- /**
- * Created on 2010-7-1
- * <p>Discription:[getAllFileType,常见文件头信息]</p>
- * @author:[shixing_11@sina.com]
- */
- private static void getAllFileType()
- {
- FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG (jpg)
- FILE_TYPE_MAP.put("png", "89504E47"); //PNG (png)
- FILE_TYPE_MAP.put("gif", "47494638"); //GIF (gif)
- FILE_TYPE_MAP.put("tif", "49492A00"); //TIFF (tif)
- FILE_TYPE_MAP.put("bmp", "424D"); //Windows Bitmap (bmp)
- FILE_TYPE_MAP.put("dwg", "41433130"); //CAD (dwg)
- FILE_TYPE_MAP.put("html", "68746D6C3E"); //HTML (html)
- FILE_TYPE_MAP.put("rtf", "7B5C727466"); //Rich Text Format (rtf)
- FILE_TYPE_MAP.put("xml", "3C3F786D6C");
- FILE_TYPE_MAP.put("zip", "504B0304");
- FILE_TYPE_MAP.put("rar", "52617221");
- FILE_TYPE_MAP.put("psd", "38425053"); //Photoshop (psd)
- FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A"); //Email [thorough only] (eml)
- FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F"); //Outlook Express (dbx)
- FILE_TYPE_MAP.put("pst", "2142444E"); //Outlook (pst)
- FILE_TYPE_MAP.put("xls", "D0CF11E0"); //MS Word
- FILE_TYPE_MAP.put("doc", "D0CF11E0"); //MS Excel 注意:word 和 excel的文件头一样
- FILE_TYPE_MAP.put("mdb", "5374616E64617264204A"); //MS Access (mdb)
- FILE_TYPE_MAP.put("wpd", "FF575043"); //WordPerfect (wpd)
- FILE_TYPE_MAP.put("eps", "252150532D41646F6265");
- FILE_TYPE_MAP.put("ps", "252150532D41646F6265");
- FILE_TYPE_MAP.put("pdf", "255044462D312E"); //Adobe Acrobat (pdf)
- FILE_TYPE_MAP.put("qdf", "AC9EBD8F"); //Quicken (qdf)
- FILE_TYPE_MAP.put("pwl", "E3828596"); //Windows Password (pwl)
- FILE_TYPE_MAP.put("wav", "57415645"); //Wave (wav)
- FILE_TYPE_MAP.put("avi", "41564920");
- FILE_TYPE_MAP.put("ram", "2E7261FD"); //Real Audio (ram)
- FILE_TYPE_MAP.put("rm", "2E524D46"); //Real Media (rm)
- FILE_TYPE_MAP.put("mpg", "000001BA"); //
- FILE_TYPE_MAP.put("mov", "6D6F6F76"); //Quicktime (mov)
- FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); //Windows Media (asf)
- FILE_TYPE_MAP.put("mid", "4D546864"); //MIDI (mid)
- }
- public static void main(String[] args) throws Exception
- {
- File f = new File("c://aaa.gif");
- if (f.exists())
- {
- String filetype1 = getImageFileType(f);
- System.out.println(filetype1);
- String filetype2 = getFileByFile(f);
- System.out.println(filetype2);
- }
- }
- /**
- * Created on 2010-7-1
- * <p>Discription:[getImageFileType,获取图片文件实际类型,若不是图片则返回null]</p>
- * @param File
- * @return fileType
- * @author:[shixing_11@sina.com]
- */
- public final static String getImageFileType(File f)
- {
- if (isImage(f))
- {
- try
- {
- ImageInputStream iis = ImageIO.createImageInputStream(f);
- Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
- if (!iter.hasNext())
- {
- return null;
- }
- ImageReader reader = iter.next();
- iis.close();
- return reader.getFormatName();
- }
- catch (IOException e)
- {
- return null;
- }
- catch (Exception e)
- {
- return null;
- }
- }
- return null;
- }
- /**
- * Created on 2010-7-1
- * <p>Discription:[getFileByFile,获取文件类型,包括图片,若格式不是已配置的,则返回null]</p>
- * @param file
- * @return fileType
- * @author:[shixing_11@sina.com]
- */
- public final static String getFileByFile(File file)
- {
- String filetype = null;
- byte[] b = new byte[50];
- try
- {
- InputStream is = new FileInputStream(file);
- is.read(b);
- filetype = getFileTypeByStream(b);
- is.close();
- }
- catch (FileNotFoundException e)
- {
- e.printStackTrace();
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- return filetype;
- }
- /**
- * Created on 2010-7-1
- * <p>Discription:[getFileTypeByStream]</p>
- * @param b
- * @return fileType
- * @author:[shixing_11@sina.com]
- */
- public final static String getFileTypeByStream(byte[] b)
- {
- String filetypeHex = String.valueOf(getFileHexString(b));
- Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
- while (entryiterator.hasNext()) {
- Entry<String,String> entry = entryiterator.next();
- String fileTypeHexValue = entry.getValue();
- if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
- return entry.getKey();
- }
- }
- return null;
- }
- /**
- * Created on 2010-7-2
- * <p>Discription:[isImage,判断文件是否为图片]</p>
- * @param file
- * @return true 是 | false 否
- * @author:[shixing_11@sina.com]
- */
- public static final boolean isImage(File file){
- boolean flag = false;
- try
- {
- BufferedImage bufreader = ImageIO.read(file);
- int width = bufreader.getWidth();
- int height = bufreader.getHeight();
- if(width==0 || height==0){
- flag = false;
- }else {
- flag = true;
- }
- }
- catch (IOException e)
- {
- flag = false;
- }catch (Exception e) {
- flag = false;
- }
- return flag;
- }
- /**
- * Created on 2010-7-1
- * <p>Discription:[getFileHexString]</p>
- * @param b
- * @return fileTypeHex
- * @author:[shixing_11@sina.com]
- */
- public final static String getFileHexString(byte[] b)
- {
- StringBuilder stringBuilder = new StringBuilder();
- if (b == null || b.length <= 0)
- {
- return null;
- }
- for (int i = 0; i < b.length; i++)
- {
- int v = b[i] & 0xFF;
- String hv = Integer.toHexString(v);
- if (hv.length() < 2)
- {
- stringBuilder.append(0);
- }
- stringBuilder.append(hv);
- }
- return stringBuilder.toString();
- }
- }
这样,不管是传入的文件有后缀名,还是无后缀名,或者修改了后缀名,真正获取到的才是该文件的实际类型,这样避免了一些想通过修改后缀名或者Content-type信息来攻击的因素。但是性能与安全永远是无法同时完美的,安全的同时付出了读取文件的代价。本人建议可采用后缀名与读取文件的方式结合校验,毕竟攻击是少数,后缀名的校验能排除大多数用户,在后缀名获取不到时再通过获取文件真实类型校验,这样来适当提高性能。
相关推荐
根据头信息判断文件类型是计算机科学中的一个常见技术,它基于这样一个事实:大多数文件格式在开始部分都会包含一些特定的字节序列,这些序列被称为“魔术数字”或“文件签名”,用于标识文件的类型。这种方法在很多...
ELF文件开始处有固定的标识符,即`e_ident`字段,它包括了文件的魔术数字和版本信息。例如,`EI_MAG0`至`EI_MAG3`分别对应于ELF文件头的前四个字节,其值应为`0x7f`, `'E'`, `'L'`, 和`'F'`,这是识别一个文件是否为...
1. **基本数据类型与变量**:游戏可能会使用整型(int)来存储数字,浮点型(float或double)处理分数,布尔型(bool)表示条件状态等。 2. **流程控制**:通过if-else语句、switch-case结构来实现游戏逻辑判断,...
- Magic Number:魔术数字是一种用于识别文件类型的技术。Linux内核可以通过魔术数字快速识别文件系统类型。 - Revision Level:修订级别是指定文件系统版本的信息。 - Mount:挂载指的是将一个文件系统加入到系统...
// 魔术数字 WORD e_cblp; // 文件最后页的字节数 WORD e_cp; // 文件页数 WORD e_crlc; // 重定义元素个数 WORD e_cparhdr; // 头部尺寸,以段落为单位 WORD e_minalloc; // 所需的最小附加段 WORD e_...
通过查看十六进制,我们可以识别出特定的文件签名或魔术数字,这些是识别文件类型的关键。例如,JPEG图像的文件头通常以“FF D8 FF E0”开始,而PE(Portable Executable)可执行文件的头两个字节是“4D 5A”。 2. ...
- **链路层类型(LinkType)**: 根据不同的链路层协议有不同的值,例如Ethernet对应的值为1。 ##### 2. 数据包头部(PacketHeader) 每个数据包之前都有一个16字节的头部,用以描述该数据包的相关信息: ```c ...
- **图像文件(idx3-ubyte)**:以二进制格式存储,前16个字节是元数据,包括魔术数字(用于识别文件类型)、图像数量、宽度、高度和颜色通道数。MNIST中的图像为单通道(灰度),所以颜色通道数为1。接下来的数据...
- 魔术数(Magic Number):用来标识文件类型; - 机器类型(Machine Type):指定目标机器架构; - 节表项数(Number Of Sections):指明文件中有多少个节; - 时间戳(Time Date Stamp):记录文件创建的时间戳;...
// 魔术数字,标识文件类型 u2 minor_version; // 次版本号 u2 major_version; // 主版本号 u2 constant_pool_count; // 常量池的元素数量 cp_info constant_pool[constant_pool_count - 1]; // 常量池 u2 ...
// 魔术数字,用于识别文件格式,通常为0xA1B2C3D4 unsigned short version_major;// 主版本号,如0x02 unsigned short version_minor;// 次版本号,如0x04 int thiszone; // GMT到本地时间的校正值,一般设为0 ...
// 魔术数字,通常为“MZ” USHORT e_cblp; // 文件最后一页的字节数 USHORT e_cp; // 文件页数 USHORT e_crlc; // 重定位元素个数 USHORT e_cparhdr; // 头部尺寸,以段落为单位 USHORT e_minalloc; // 所需...
- **魔术数**:文件头部分的魔法数字用于标识文件类型,这里使用`"MELF"`作为标志。 - **文件大小与内存大小**:`e_filesz`表示文件实际大小,而`e_memsz`则表示包含bss段在内的文件在内存中的总大小。 - **动态段...
- `e_type`: 文件类型,如可执行文件、目标文件等。 - `e_machine`: 目标机器架构,如`EM_X86_64`表示x86_64架构。 - `e_version`: 文件版本。 - `e_entry`: 程序入口地址。 - `e_phoff`: 程序头表相对于文件...
- **魔术数字**:通常为16进制的`0xa1b2c3d4`,用于确认文件格式。 - **版本号**:默认为主版本号`0x02`和次版本号`0x04`。 - **GMT到本地时间校正**:此字段未使用,一般设为0。 - **时间戳精度**:此字段也未使用...
在字符串拼接操作中,不同类型的值会被转换为字符串,如`NULL`会变成空字符串,布尔值`true`会转换为字符串`'1'`,`false`转换为空字符串。 - **强制类型转换**:可以使用类型转换函数如`intval`、`strval`和`...
在源代码中,程序员通常会使用结构体来表示DOS头,包括魔术数字(识别文件类型的标识),程序的起始地址,代码和数据段的大小等。例如: ```c struct dos_header { unsigned char magic; // 魔术数字,通常是'NE' ...
解压后,文件分为四部分:32位的魔术数字标识文件类型,32位的图像数量,32位的行数(28),和32位的列数(28)。接着是每个像素的值,是0到255之间的整数,表示灰度级别。 2. `train-labels-idx1-ubyte.gz`:这是...
这些序列称为魔术数字或文件签名。例如,一个PNG图片文件的头两个字节通常是0x89 0x50(在十进制中是137 80),它们被用来唯一地识别PNG文件。 在PHP中,我们可以使用标准的文件处理函数来读取文件的头部信息。具体...
- **文件头块**:定义了文件的基本属性,如魔术数字、主要版本号、次要版本号等。 - **接口描述块**:描述捕获数据的接口信息,包括接口ID、接口类型等。 - **简单包块**:包含了捕获到的数据包的信息,包括时间戳、...