Как проверить, является ли exe-файл с расширением, измененным на csv, на самом деле файлом csv с #
Поэтому мне нужно создать средство проверки файлов, которое может проверить правильность типа файла. Первоначально мы просто проверяли тип содержимого запроса, но, как всегда, нашим тестерам удалось обойти ограничение, просто изменив расширение файла в случае exe-файла на.csv, что может обмануть нашу простую проверку.
Это то, что у меня пока есть в валидаторе
private bool IsCorrectFileType(IFormFile file)
{
using var reader = new StreamReader(file.OpenReadStream());
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
try
{
csv.Read();
csv.ReadHeader();
List<string> headers = csv.Context.HeaderRecord.ToList();
}
catch (Exception _)
{
return false;
}
return true;
}
Я собирался сделать следующее: если читатель CSV не может найти заголовки в файле, тогда я надеялся, что он взорвется и вернет false, но что происходит, так это то, что полное содержимое файла читается как один заголовок в все ситуации с файлами, отличными от CSV. заставляя его думать, что это действительно действительный файл csv, и возвращать истину.
Я не могу на всю жизнь разработать способ определить, действительно ли файл CSV действителен, поскольку в большинстве случаев читатель CSV может читать во всех потоках как байтовые данные, а контекст записи заголовка выглядит как действительный CSV в этом кейс.
Что раздражает, так как мы никогда не будем загружать файл с одним заголовком, кажется глупым просто провести стандартный подсчет заголовков, чтобы увидеть, есть ли у него только один заголовок, чтобы выявить эту проблему.
Любая помощь будет оценена по достоинству, так как я немного озадачен этим. Заранее спасибо, Крис.
2 ответа
Вот как бы я это сделал.
Проверьте файл на наличие байтов 0x00. Обычно они встречаются в двоичных файлах, но не разрешены в текстовых файлах, за исключением, возможно, самого конца в качестве нулевого терминатора. Так что это может быть относительно быстрая проверка работоспособности.
Разделите файл на строки (например, разделите на разделители строк
\n
а также\r
), затем проверьте каждую строку, чтобы убедиться, что в ней одинаковое количество запятых. Обратите внимание, что в некоторых столбцах могут быть запятые, и вы не должны их считать; столбец, содержащий встроенные запятые, будет заключен в кавычки, чтобы избежать их. Итак, вам нужно написать небольшой код, чтобы проанализировать строку и произвести подсчет.Если оба вышеуказанных шага пройдут, возможно, файл недействителен, например, если он содержит недопустимые последовательности UTF. Посмотрите этот пост, если вы хотите проверить их.
Если вы знаете что-то о том, что должно быть в файле, используйте регулярные выражения для проверки каждой строки и столбца, чтобы убедиться, что файл действителен в целом.
Вы можете реализовать только шаг 1, описанный выше, или шаги 1 и 2, или все из них, в зависимости от того, насколько это важно.
После экспериментов с тем, как выглядит строка типа, отличного от csv, в контексте заголовка парсеров csv, я смог утверждать, была ли это просто треп, то есть содержимое exe или jpg, и поэтому он будет содержать символы, отличные от ascii, в длинной строке.
В приведенном ниже коде показано, что я сделал, чтобы проверить, так ли это. если да, он отклоняет его, если не позволяет проглотить.
/// <summary>
/// Minimises chances of incorrect file types being passed to the service that have been
/// maliciously changed to a csv format when the original is for example .exe .jpg and so on.
/// </summary>
/// <remarks>
/// The function below checks if a header row exists in the incoming file. In all cases where the CsvReader is
/// able to read the file it will either create a list of headers if the file is valid or subsequently if the file
/// uploaded has been modifed to look like a csv file the Context.HeaderRecord will read in all of the content to a
/// single header. If there is only one header in the file to make sure the file is valid I an running a string function
/// on the header to make sure it definitely includes ascii charachters if not in the case of any file thats malliciously
/// been changed it will load all of the bytes into the headerRecord which means it will fail the chack and fail validation.
/// This will in turn minimise the chances of a malicious file thats had its name changed name changed from hitting the file processor.
/// </remarks>
private bool IsCsvFileFormat(IFormFile file)
{
using var reader = new StreamReader(file.OpenReadStream());
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
try
{
csv.Read();
csv.ReadHeader();
var headerRecordList = csv.Context.HeaderRecord.ToList();
if (headerRecordList.Count() == 1)
return !HasNonASCIIChars(headerRecordList.ElementAt(0));
}
catch (Exception _)
{
return false;
}
return true;
}
private bool HasNonASCIIChars(string str) =>
(System.Text.Encoding.UTF8.GetByteCount(str) != str.Length);