実際のファイルタイプを調べる
-
19-08-2019 - |
質問
ファイルのアップロードを処理するASP Webページで作業しています。 .XLS、.XML、.CSV、.TXT、.PDF、.PPTなど、特定の種類のファイルのみをアップロードできます。
ファイルが実際に拡張子と同じタイプかどうかを判断する必要があります。つまり、 trojan.exe の名前が harmless.pdf に変更されてアップロードされた場合、アプリケーションはアップロードされたファイルが.PDFファイルではないことを検出できる必要があります。
これらのアップロードされたファイルを分析するためにどのようなテクニックを使用しますか?これらのファイルの形式に関する最適な情報はどこで入手できますか?
解決
1つの方法は、ファイル内の特定の署名またはマジックナンバーをチェックすることです。このページには、既知のファイル署名の便利なリストがあり、かなり最新のようです:
他のヒント
つまり、trojan.exeの名前がharmless.pdfに変更されてアップロードされた場合、アプリケーションは、アップロードされたファイルが.PDFファイルではないことを検出できる必要があります。
それは実際には問題ではありません。 .exeが.pdfとしてアップロードされ、それをapplication / pdfとしてダウンローダーに正しく提供した場合、ダウンローダーが取得するのは壊れたPDFになります。被害を受けるには、手動で.exeに再入力する必要があります。
実際の問題は次のとおりです。
-
一部のブラウザは、ファイルの内容を盗聴し、ファイルの種類についてあなたよりもよく知っていると判断する場合があります。 IEはこの点で特に悪く、ファイルの先頭近くに潜んでいるHTMLタグが見つかった場合、ファイルをHTMLとしてレンダリングすることを好む傾向があります。これは、スクリプトがサイトに挿入される可能性があり、アプリケーションレベルのセキュリティを侵害する可能性があるため、特に役に立ちません(cookie stealing et al)。回避策には、常にContent-Dispositionを使用して添付ファイルとしてファイルを提供すること、および/または別のホスト名からファイルを提供することが含まれます。
-
とにかくPDFファイルは安全ではありません!スクリプトでいっぱいになる可能性があり、重大なセキュリティホールがあります。 PDFリーダーブラウザプラグインの穴を悪用することは、現在、Webにトロイの木馬をインストールする最も一般的な方法の1つです。そして、高度に難読化される可能性があるため、エクスプロイトの検出を試みるために通常できることはほとんどありません。
<!> quot; safe <!> quot;のファイルヘッダーを取得します。ファイルの種類-実行可能ファイルには常に独自の種類のヘッダーがあり、おそらくそれらを検出できます。ただし、受け入れる予定のすべての形式に精通している必要があります。
C#と言ったのは知っていますが、これは移植できるかもしれません。また、一般的なファイルタイプの多くの記述子がすでに含まれているXMLファイルがあります。
これは、JMimeMagicと呼ばれるJavaライブラリです。ここにあります: http://jmimemagic.sourceforge.net/
** NIX *システムには、 file(1)というユーティリティがあります。 Windowsに似たものを見つけようとしますが、selfが移植されている場合はファイルユーティリティを探します。
別の方向からアプローチすることもできます。アップロードされるすべてのファイルの種類を識別するのではなく(最近ではいくつかの形式があるため、Excelだけでは混乱のように思えます)、すべてのアップロードをウイルススキャナーで実行するのはなぜですか?さまざまなファイルにウイルスやトロイの木馬が含まれている可能性があります。サーバーにとってはより多くの作業が必要になる場合がありますが、最も安全なソリューションです。
その後、ファイルの種類を正しく識別するのはユーザーの責任です。ユーザーを再確認するためだけに多くのコードを追加することも(テストする必要があります)、大きなステップのように思えます。 .pdf2ファイルだと言う場合、.pdfに名前を変更しますか?これが企業環境にある場合、ユーザーがファイルに正しい拡張子を持っていることを期待するのは合理的です。誰が何をアップロードしたかも追跡します。公開されている場合は、ファイルの種類をスキャンする価値があるかもしれませんが、ウイルススキャンも絶対に行います。
次の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;
}