9

我有一个用例,我们允许用户上传文件。现在在后端java(从http请求中提取文件并检查的控制器)中,我想检测用户是否上传了任何可执行文件。如果他上传,我必须丢弃该文件。我用谷歌搜索了它,但找不到一个好的解决方案。有些人建议验证扩展名(.exe)。但我不确定它将过滤 exe 文件多远。我想完全阻止上传可执行文件。

如果你们中的任何人遇到过这种情况或对此有解决方案,请告诉我。我会很感激你的。

如果您能指出任何可以完成这项工作的 JAVA 实现或 Java API 或算法,我会更高兴。

4

6 回答 6

11

我怀疑,除了你已经提到的扩展检查方法之外,没有办法捕捉所有可能的情况。可执行文件最终是机器指令序列,这使得它们在很大程度上与任何其他数据无法区分。

尽管如此,您仍然可以在某些类型的可执行文件中寻找一些东西。例如:

  • Windows 使用Portable Executable格式,该格式应始终以幻数4d5a(ASCII 字符MZ)开头
  • Linux 使用的 ELF格式可执行文件以7f454c46
  • Java 类文件cafebabe总是以(那是十六进制,而不是 ASCII!)开头。
  • 据我所知,Mac-OSX 使用的 Mach-O 文件有一个幻数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();
  }
}

另请注意,可能会出现误报,即拒绝不可执行的文件。我不知道您打算上传什么类型的文件,因此您应该考虑发生这种情况的可能性有多大。

于 2013-02-10T16:52:48.697 回答
1

完成 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;
    }
于 2019-02-28T14:39:28.387 回答
0

Windows 可执行文件总是以MZ幻数开头。可能你可以检查一下。

于 2013-02-10T16:43:27.357 回答
0

据我所知,最常用的方法是验证扩展名。例如,我注意到如果将可执行文件重命名为 zip 或其他扩展名,邮件客户端通常会接受发送该可执行文件。
我相信这似乎足够了,因为安全问题是如果用户不小心运行了可执行文件。通过将文件重命名为未知/不同的扩展名,用户不会意外地这样做,因此危险会以某种方式“减轻”
否则想出一种方法来查看文件内容以确定您是否真的有可执行文件,我不不知道这是多么可行/便携/可靠

于 2013-02-10T16:49:42.647 回答
0

看看这里:

有没有一种好方法可以确定文件是否可以在 Java 中执行

似乎此命令可能会有所帮助: java.io.File.canExecute()

于 2013-02-10T16:50:09.200 回答
0

请注意,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从其内容中获取文件类型

于 2013-02-10T17:03:16.740 回答