我有一个用例,我们允许用户上传文件。现在在后端java(从http请求中提取文件并检查的控制器)中,我想检测用户是否上传了任何可执行文件。如果他上传,我必须丢弃该文件。我用谷歌搜索了它,但找不到一个好的解决方案。有些人建议验证扩展名(.exe)。但我不确定它将过滤 exe 文件多远。我想完全阻止上传可执行文件。
如果你们中的任何人遇到过这种情况或对此有解决方案,请告诉我。我会很感激你的。
如果您能指出任何可以完成这项工作的 JAVA 实现或 Java API 或算法,我会更高兴。
我有一个用例,我们允许用户上传文件。现在在后端java(从http请求中提取文件并检查的控制器)中,我想检测用户是否上传了任何可执行文件。如果他上传,我必须丢弃该文件。我用谷歌搜索了它,但找不到一个好的解决方案。有些人建议验证扩展名(.exe)。但我不确定它将过滤 exe 文件多远。我想完全阻止上传可执行文件。
如果你们中的任何人遇到过这种情况或对此有解决方案,请告诉我。我会很感激你的。
如果您能指出任何可以完成这项工作的 JAVA 实现或 Java API 或算法,我会更高兴。
我怀疑,除了你已经提到的扩展检查方法之外,没有办法捕捉所有可能的情况。可执行文件最终是机器指令序列,这使得它们在很大程度上与任何其他数据无法区分。
尽管如此,您仍然可以在某些类型的可执行文件中寻找一些东西。例如:
4d5a
(ASCII 字符MZ
)开头7f454c46
cafebabe
总是以(那是十六进制,而不是 ASCII!)开头。feedface
(又是十六进制)我建议您创建一个FileInputStream
或类似的文件并读取文件的前几个字节,检查这些幻数。它没有检测到任何包含可执行代码的文件,但它应该阻止这些标准可执行格式的文件被允许,我认为这是你所希望的。
例如:
public static boolean isExecutable(File file) {
byte[] firstBytes = new byte[4];
try {
FileInputStream input = new FileInputStream(file);
input.read(firstBytes);
// Check for Windows executable
if (firstBytes[0] == 0x4d && firstBytes[1] == 0x5a) {
return true;
}
return false;
}
catch (Exception e) {
e.printStackTrace();
}
}
另请注意,可能会出现误报,即拒绝不可执行的文件。我不知道您打算上传什么类型的文件,因此您应该考虑发生这种情况的可能性有多大。
完成 devrobf 的响应: 每个可执行文件(我的意思是该文件包含机器指令)都可以通过文件元数据中包含的幻数来识别。幻数由它的大小(以字节为单位)和它的偏移量(根据文件类型可能不同)来标识。您可以在此处找到包含此信息的数据库。
例如 EXE 文件:
Extension : EXE
Signature : 4D 5A
Description : Windows|DOS executable file
MZ (ASCII)
Sizet : 2 Bytes
Offset: 0 Bytes
正如您肯定会理解的那样,仅对扩展名进行检查并不能确定确定什么样的可执行文件。作为提议的Cratylus。为什么?因为下面的例子:
touch notAnExecutableWithExtensionExe.exe
该命令只是创建扩展名为“exe”的文件,但它只是文件数据。
用 Java 实现对任何类型的文件进行正确检查:
public enum ExecutableSignatures{
WINDOWS_EXE("Windows|DOS executable file", (byte) 0x00, (byte) 0x02,
new byte[]{(byte)0x4d, (byte)0x5a}),
JAVA_BYTECODE("Java Bytecode", (byte) 0x00, (byte) 0x04,
new byte[]{(byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe});
/* Here more enumeration */
private String description;
private byte offset;
private byte size;
private byte[] magicNumber;
private ExecutableSignatures(String description, byte offset, byte size, byte [] magicNumber){
this.description = description;
this.offset = offset;
this.size = size;
this.magicNumber = magicNumber;
}
public String getDescription(){
return this.description;
}
public byte getOffset(){
return this.offset;
}
public byte getSize(){
return this.size;
}
public byte[] getMagicNumbers(){
return this.magicNumber;
}
在您可以通过使用 apache 库创建方法来进行此检查后,请参阅此处, 请参阅 @Filters - MagicNumberFilter。此构造函数可以采用 2 个参数;magicNumbers(字节数组)和偏移量(字节)。
/**
* Perform a check of what kind of executable is by checking the signature
* of file.
* If it's an executable that is enumerate then the attributes
* magicNumber and executableDescription are updated with their corresponding
* values.
* @return true if is an executable supported by the program otherwise false
*/
public boolean isExecutableFile(){
MagicNumberFileFilter mnff = null;
for(ExecutableSignatures es : EnumSet.allOf(ExecutableSignatures.class)){
mnff = new
MagicNumberFileFilter(es.getMagicNumbers(), es.getOffset());
if(mnff.accept(this.file)){
this.magicNumber = es.getMagicNumbers();
this.executableDescription = es.getDescription();
return true;
}
}
return false;
}
Windows 可执行文件总是以MZ
幻数开头。可能你可以检查一下。
据我所知,最常用的方法是验证扩展名。例如,我注意到如果将可执行文件重命名为 zip 或其他扩展名,邮件客户端通常会接受发送该可执行文件。
我相信这似乎足够了,因为安全问题是如果用户不小心运行了可执行文件。通过将文件重命名为未知/不同的扩展名,用户不会意外地这样做,因此危险会以某种方式“减轻”
否则想出一种方法来查看文件内容以确定您是否真的有可执行文件,我不不知道这是多么可行/便携/可靠
请注意,Windows 可执行文件不仅是.exe
文件,因此检查扩展名是不够的
如果您想要一些高级且难以愚弄的东西,您可以使用第三方工具,例如File for Windows,它是一种从 Linux 移植的流行命令行工具。
例如,如果你想检查某个文件program.exe
C:\file -b "program.exe"
结果将类似于
PE32 executable for MS Windows <GUI> Intel
您可以使用从 Java 程序运行此工具Runtime.getRuntime().exec()
请参阅此问题以了解如何运行命令行程序并获取 Java 输出
您还可以检查Apache Tika从其内容中获取文件类型