而对于上传文件来说,不能简单的通过后缀名来判断文件的类型,因为恶意攻击可以将可执行文件的后缀名称改为图片或者其他格式,诱导用户执行,因此,判断上传文件的类型需要更安全的方式。
1. 文件上传的API
引入依赖:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
API说明
Apache commons io FileUtils、IOUtils 详解
测试代码:
FileUtils.readFileToByteArray(new File("/Users/libai/Documents/xwc.jpeg"));
2. 文件魔数
与Java的class文件类似,很多类型的文件,起始的几个字节内容都是固定的,跟据这几个字节的内容,就可以判断文件的类型,这几个字节也被称为“魔数”,比如class文件的魔数就是“CAFEBABE”。
通过魔数判断文件类型便是一种更安全的方式,其示例源码如下。
魔数枚举类:
import lombok.Getter;
@Getter
public enum FileType {
/**
* JPEG
*/
JPEG("FFD8FF"),
/**
* PNG
*/
PNG("89504E47"),
/**
* GIF
*/
GIF("47494638"),
/**
* TIFF
*/
TIFF("49492A00"),
/**
* Windows bitmap
*/
BMP("424D"),
/**
* CAD
*/
DWG("41433130"),
/**
* Adobe photoshop
*/
PSD("38425053"),
/**
* Rich Text Format
*/
RTF("7B5C727466"),
/**
* XML
*/
XML("3C3F786D6C"),
/**
* HTML
*/
HTML("68746D6C3E"),
/**
* Outlook Express
*/
DBX("CFAD12FEC5FD746F "),
/**
* Outlook
*/
PST("2142444E"),
/**
* doc;xls;dot;ppt;xla;ppa;pps;pot;msi;sdw;db
*/
OLE2("0xD0CF11E0A1B11AE1"),
/**
* Microsoft Word/Excel
*/
XLS_DOC("D0CF11E0"),
/**
* Microsoft Access
*/
MDB("5374616E64617264204A"),
/**
* Word Perfect
*/
WPB("FF575043"),
/**
* Postscript
*/
EPS_PS("252150532D41646F6265"),
/**
* Adobe Acrobat
*/
PDF("255044462D312E"),
/**
* Windows Password
*/
PWL("E3828596"),
/**
* ZIP Archive
*/
ZIP("504B0304"),
/**
* ARAR Archive
*/
RAR("52617221"),
/**
* WAVE
*/
WAV("57415645"),
/**
* AVI
*/
AVI("41564920"),
/**
* Real Audio
*/
RAM("2E7261FD"),
/**
* Real Media
*/
RM("2E524D46"),
/**
* Quicktime
*/
MOV("6D6F6F76"),
/**
* Windows Media
*/
ASF("3026B2758E66CF11"),
/**
* MIDI
*/
MID("4D546864");
private String value;
FileType(String value) {
this.value = value;
}
}
魔数校验类
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileUtil {
/**
* 判断文件类型
*/
public static FileType getType(String filePath) throws IOException {//获取文件头
String fileHead = getFileHeader(filePath);
if (fileHead != null && fileHead.length() > 0) {
fileHead = fileHead.toUpperCase();
FileType[] fileTypes = FileType.values();
for (FileType type : fileTypes) {
if (fileHead.startsWith(type.getValue())) {
return type;
}
}
}
return null;
}
public static FileType getType(byte[] bytes) throws IOException {//获取文件头
String fileHead = bytesToHex(bytes);
if (fileHead != null && fileHead.length() > 0) {
fileHead = fileHead.toUpperCase();
FileType[] fileTypes = FileType.values();
for (FileType type : fileTypes) {
if (fileHead.startsWith(type.getValue())) {
return type;
}
}
}
return null;
}
/**
* 读取文件头
*/
private static String getFileHeader(String filePath) throws IOException {
byte[] b = new byte[28];
InputStream inputStream = null;
try {
inputStream = new FileInputStream(filePath);
inputStream.read(b, 0, 28);
} finally {
if (inputStream != null) {
inputStream.close();
}
}
return bytesToHex(b);
}
/**
* 将字节数组转换成16进制字符串
*/
public static String bytesToHex(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}
网友评论