如何更好的判断系统上传文件是指定文件类型--文件魔术数字
2016-03-03 15:06
411 查看
理论介绍
这里所说的表示不同文件类型的魔术数字,指定是文件的最开头的几个用于唯一区别其它文件类型的字节,有了这些魔术数字,我们就可以很方便的区别不同的文件,这也使得编程变得更加容易,因为我减少了我们用于区别一个文件的文件类型所要花费的时间。比如,一个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 | ¦. |
java实现(图片类型判断)
使用魔术数字判断
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class ImageTypeCheck { public static String bytesToHexString(byte[] src) { StringBuilder stringBuilder = new StringBuilder(); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { // byte转int int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } public static void main(String[] args) throws IOException { String imagePath = "c:/favicon.png"; File image = new File(imagePath); InputStream is = new FileInputStream(image); byte[] bt = new byte[2]; is.read(bt); System.out.println(bytesToHexString(bt)); } }
使用图片长宽判断
如果能够正常的获取到一张图片的宽高属性,那肯定这是一张图片,因为非图片文件我们是获取不到它的宽高属性的,以下是用于获取根据是否可以获取到图片宽高属性来判断这是否一张图片的JAVA代码:/** * 通过读取文件并获取其width及height的方式,来判断判断当前文件是否图片,这是一种非常简单的方式。 * * @param imageFile * @return */ public static boolean isImage(File imageFile) { if (!imageFile.exists()) { return false; } Image img = null; try { img = ImageIO.read(imageFile); if (img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) { return false; } return true; } catch (Exception e) { return false; } finally { img = null; } }
好了,我们终于判断出一个文件是否图片了,可是如果是在一个可以正常浏览的图片文件中加入一些非法的代码呢:
这就是在一张正常的图片末尾增加的一些iframe代码,我曾经尝试过单独打开这张图片,也将这张图片放于网页上打开,虽然这样都不会被执行,但并不代表插入其它的代码也并不会执行,杀毒软件(如AVAST)对这种修改是会报为病毒的。
那我们要如何预防这种东西,即可以正常打开,又具有正确的图片文件扩展名,还可以获取到它的宽高属性?呵,我们这个时候可以对这个图片进地重写,给它增加水印或者对它进行resize操作,这样新生成的图片就不会再包含这样的恶意代码了,以下是一个增加水印的JAVA实现:
增加水印的JAVA实现
/** * 添加图片水印 * * @param srcImg 目标图片路径,如:C:\\kutuku.jpg * @param waterImg 水印图片路径,如:C:\\kutuku.png * @param x 水印图片距离目标图片左侧的偏移量,如果x<0, 则在正中间 * @param y 水印图片距离目标图片上侧的偏移量,如果y<0, 则在正中间 * @param alpha 透明度(0.0 -- 1.0, 0.0为完全透明,1.0为完全不透明) * @throws IOException */ public final static void addWaterMark(String srcImg, String waterImg, int x, int y, float alpha) throws IOException { // 加载目标图片 File file = new File(srcImg); String ext = srcImg.substring(srcImg.lastIndexOf(".") + 1); Image image = ImageIO.read(file); int width = image.getWidth(null); int height = image.getHeight(null); // 将目标图片加载到内存。 BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = bufferedImage.createGraphics(); g.drawImage(image, 0, 0, width, height, null); // 加载水印图片。 Image waterImage = ImageIO.read(new File(waterImg)); int width_1 = waterImage.getWidth(null); int height_1 = waterImage.getHeight(null); // 设置水印图片的透明度。 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); // 设置水印图片的位置。 int widthDiff = width - width_1; int heightDiff = height - height_1; if (x < 0) { x = widthDiff / 2; } else if (x > widthDiff) { x = widthDiff; } if (y < 0) { y = heightDiff / 2; } else if (y > heightDiff) { y = heightDiff; } // 将水印图片“画”在原有的图片的制定位置。 g.drawImage(waterImage, x, y, width_1, height_1, null); // 关闭画笔。 g.dispose(); // 保存目标图片。 ImageIO.write(bufferedImage, ext, file); }
整理参考:
/article/2658322.html
/content/1894754.html
相关文章推荐
- Perl - File I/O
- java有参构造方法和无参构造方法
- 反编译技巧
- 16-3-3代码
- 给ListBox每项加图标
- 系统出现tcpip临时端口不够用
- SmartClient
- nginx的配置系统
- 简单说明多态
- sonarQube的配置和使用(在本地安装)
- setOnItemSelectedListener、setOnItemClickListener与setOnTouchlistener的区别
- spark入门实战
- doPost和doGet方法的区别
- [JavaScript][表单文本框&下拉列表框操作]
- 移动分区表和分区索引的表空间
- HDU1698Just a Hook(线段树 + 区间修改 + 求和)
- <php>删除(有内容的)文件夹函数程序
- Java NIO使用及原理分析 (三)
- split,csplit命令:文件切割
- IOS APPStore上架流程