查找真实文件类型

7
我正在处理一个ASP网页,负责文件上传操作。只有特定类型的文件可以被上传,如.XLS,.XML,.CSV,.TXT,.PDF,.PPT等。
我需要判断文件是否与其扩展名所示的类型相同。换句话说,如果将trojan.exe重命名为harmless.pdf并上传,应用程序必须能够找出上传的文件不是.PDF文件。
你会使用什么技术来分析这些上传的文件?在哪里可以获得有关这些文件格式的最佳信息?
7个回答

4

4
换句话说,如果一个trojan.exe被重命名为harmless.pdf并上传,应用程序必须能够找出上传的文件不是PDF文件。
这并不是真正的问题。如果一个.exe被上传为.pdf,并且你正确地将其作为application/pdf返回给下载者,下载者得到的只是一个破碎的PDF文件。他们必须手动重新键入它为.exe才会受到伤害。
真正的问题是:
1. 一些浏览器可能会检查文件内容并决定自己更好地知道文件类型。IE在这方面特别糟糕,倾向于在文件开头附近发现任何HTML标记时将文件呈现为HTML。这特别不方便,因为它意味着脚本可以注入到您的网站上,可能危及任何应用级安全性(如cookie窃取等)。解决方法包括始终使用Content-Disposition作为附件提供文件,和/或从不同的主机名提供文件,以便它无法跨站点脚本回到您的主站点。
2. PDF文件本身就不安全!它们可能充满脚本,并具有显着的安全漏洞。利用PDF阅读器浏览器插件中的漏洞目前是在Web上安装木马的最常见方式之一。通常几乎无法检测到这些漏洞的利用,因为它们可以高度混淆。

3

获取“安全”文件类型的文件头 - 可执行文件始终具有自己的文件头类型,您可能可以检测到这些文件头。但是,您必须熟悉您打算接受的每种格式。


2
我知道你说的是C#,但这可能可以移植。此外,它已经包含了许多常见文件类型的描述符的XML文件。
这是一个名为JMimeMagic的Java库。在这里:http://jmimemagic.sourceforge.net/

1
也许你可以从不同的角度来考虑这个问题。与其识别所有上传的文件类型(仅 Excel 就对我来说很混乱,因为它有几种格式),为什么不通过病毒扫描器运行所有上传的文件呢?各种各样的文件都可能包含病毒和木马。这可能会给您的服务器带来更多的工作量,但这是最安全的解决方案。

然后就由用户正确地识别他们的文件类型,这似乎是合理的。添加大量代码(还需要测试)只是为了再次检查您的用户似乎是一个很大的步骤。如果我说这是一个 .pdf2 文件,你会将其重命名为 .pdf 吗?如果这是在企业环境中,那么期望用户在其文件上具有正确的扩展名是合理的。我也会跟踪谁上传了什么。如果是公共的,则扫描文件类型可能是值得的,但我绝对会进行病毒扫描。


1
在*NIX系统中,我们有一个叫做file(1)的实用程序。尝试在Windows中找到类似的东西,但是文件实用程序本身已经被移植了。

0
以下是相关的 C++ 代码:
//-1 : File Does not Exist or no access
//0 : not an office document
//1 : (General) MS office 2007
//2 : (General) MS office older than 2007
//3 : MS office 2003 PowerPoint presentation
//4 : MS office 2003 Excel spreadsheet
//5 : MS office applications or others 
int IsOffice2007OrOlder(wchar_t * fileName)
{
    int iRet = 0;
    byte msgFormatChk2007[8]    = {0x50, 0x4B, 0x03, 0x04, 0x14, 0x00, 0x06, 0x00};     //offset 0 for office 2007 documents
    byte possibleMSOldOffice[8] = {0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1};     //offset 0 for possible office 2003 documents

    byte msgFormatChkXLSPPT[4]  = {0xFD, 0xFF, 0xFF, 0xFF};     // offset 512: xls, ppt: FD FF FF FF 
    byte msgFormatChkOnlyPPT[4] = {0x00, 0x6E, 0x1E, 0xF0};     // offset 512: another ppt offset PPT   
    byte msgFormatChkOnlyDOC[4] = {0xEC, 0xA5, 0xC1, 0x00};     //offset 512: EC A5 C1 00 
    byte msgFormatChkOnlyXLS[8] = {0x09, 0x08, 0x10, 0x00, 0x00, 0x06, 0x05, 0x00};     //offset 512: XLS

    int iMsgChk = 0;
    HANDLE fileHandle = CreateFile(fileName, GENERIC_READ,
        FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL  );
    if(INVALID_HANDLE_VALUE == fileHandle) 
    { 
        return -1; 
    }

    byte buff[20];
    DWORD bytesRead;
    iMsgChk = 1;
    if(0 == ReadFile(fileHandle, buff, 8, &bytesRead, NULL )) 
    { 
        return -1; 
    }

    if(buff[0] == msgFormatChk2007[0]) 
    {
        while(buff[iMsgChk] == msgFormatChk2007[iMsgChk] && iMsgChk < 9)
            iMsgChk++;

        if(iMsgChk >= 8) {  
            iRet = 1; //office 2007 file format
        }
    } 
    else if(buff[0] == possibleMSOldOffice[0])
    {
        while(buff[iMsgChk] == possibleMSOldOffice[iMsgChk] && iMsgChk < 9)
            iMsgChk++;

        if(iMsgChk >= 8)
        {   
            //old office file format, check 512 offset further in order to filter out real office format
            iMsgChk = 1;
            SetFilePointer(fileHandle, 512, NULL, FILE_BEGIN);
            if(ReadFile(fileHandle, buff, 8, &bytesRead, NULL ) == 0) { return 0; }

            if(buff[0] == msgFormatChkXLSPPT[0])
            {
                while(buff[iMsgChk] == msgFormatChkXLSPPT[iMsgChk] && iMsgChk < 5)
                    iMsgChk++;

                if(iMsgChk == 4)
                    iRet = 2;
            }
            else if(buff[iMsgChk] == msgFormatChkOnlyDOC[iMsgChk])
            {
                while(buff[iMsgChk] == msgFormatChkOnlyDOC[iMsgChk] && iMsgChk < 5)
                    iMsgChk++;
                if(iMsgChk == 4)
                    iRet = 2;

            }
            else if(buff[0] == msgFormatChkOnlyPPT[0])
            {
                while(buff[iMsgChk] == msgFormatChkOnlyPPT[iMsgChk] && iMsgChk < 5)
                    iMsgChk++;

                if(iMsgChk == 4)
                    iRet = 3;
            }
            else if(buff[0] == msgFormatChkOnlyXLS[0])
            {

                while(buff[iMsgChk] == msgFormatChkOnlyXLS[iMsgChk] && iMsgChk < 9)
                    iMsgChk++;

                if(iMsgChk == 9)
                    iRet = 4;
            } 

            if(0 == iRet){
                iRet = 5;
            }
        }
    }


    CloseHandle(fileHandle);

    return iRet;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接