检测java中的可执行文件



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

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

如果你能给我指一下做这项工作的任何JAVA实现或JAVA API或算法,我会更高兴。

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

尽管如此,在某些类型的可执行文件中还是可以找到一些东西。例如:

  • Windows使用可移植可执行文件格式,该格式应始终以幻数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();
  }
}

还要注意,可能会出现误报,即拒绝不可执行的文件。我不知道你打算上传什么类型的文件,所以你应该考虑这种情况发生的可能性。

要完成devrobf的响应:每个可执行文件(我的意思是文件包含机器指令)都可以通过文件元数据中包含的幻数来识别。幻数由其大小(以字节为单位)和偏移量(根据文件类型的不同,偏移量可能不同)来识别。你可以在这里找到一个包含这些信息的数据库。

例如EXE文件:

Extension :     EXE     
Signature :     4D 5A
Description :   Windows|DOS executable file
MZ (ASCII)  
Sizet :         2 Bytes
Offset:         0 Bytes

正如您肯定会理解的那样,只检查扩展名并不能确定什么样的可执行文件。就像拟议中的克拉提卢斯。为什么?因为以下示例:

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或其他扩展名,邮件客户端通常会接受发送可执行文件
我相信这似乎足够了,因为安全问题是如果用户意外地运行了可执行文件。通过将文件重命名为未知/不同的扩展名,用户不会意外地这样做,因此在某种程度上"减轻"了危险
否则,我不知道有多可行/可移植/可靠

看看这里:

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

看起来这个命令可能会有所帮助:java.io.File.canExecute()

请注意,windows可执行文件不仅仅是.exe文件,因此检查扩展名是不够的

如果你想要一些高级且难以愚弄的东西,你可以使用像File for Windows这样的第三方工具——这是一个从Linux移植而来的流行命令行工具。

例如,如果要检查某个文件program.exe

C:file -b "program.exe"

结果将类似

PE32 executable for MS Windows <GUI> Intel

您可以使用Runtime.getRuntime().exec() 从Java程序运行此工具

请参阅此问题,了解如何运行命令行程序并在Java 中获得输出

您还可以检查Apache Tika以从其内容中获取文件类型

相关内容

  • 没有找到相关文章

最新更新