December 18, 2023

MIME тип файла

Проверка MIME-типа при рендеринге страницы на сервере Node.js может дать следующие преимущества:

  • Безопасность: проверка MIME-типа может помочь защитить ваш сервер от атак с использованием вредоносных файлов. Например, если вы разрешаете только файлы изображений, вы можете предотвратить загрузку на сервер вредоносных файлов, которые могут содержать вирусы или другие вредоносные программы.
  • Надежность: проверка MIME-типа может помочь обеспечить правильную обработку файлов. Например, если вы отправляете файл JavaScript на сервер, вы хотите убедиться, что сервер обрабатывает его как JavaScript, а не как какой-либо другой тип файла.
  • Удобство: проверка MIME-типа может упростить обработку файлов. Например, если вы знаете, что файл является изображением, вы можете использовать соответствующие библиотеки и инструменты для его обработки.

В частности, проверка MIME-типа может помочь защитить ваш сервер от следующих атак:

  • XSS-атаки: XSS-атаки используются для внедрения вредоносного кода в веб-страницы. Проверка MIME-типа может помочь предотвратить загрузку на сервер файлов, которые могут содержать вредоносный код.
  • Фишинговые атаки: фишинговые атаки используются для обмана пользователей с целью получения их личных данных. Проверка MIME-типа может помочь предотвратить загрузку на сервер файлов, которые могут использоваться для фишинговых атак.
  • Заражение вирусами: вирусы могут распространяться через файлы. Проверка MIME-типа может помочь предотвратить загрузку на сервер файлов, которые могут содержать вирусы.

Конечно, проверка MIME-типа не является панацеей от всех атак. Однако она является важным шагом к обеспечению безопасности вашего сервера.

Вот несколько советов по проверке MIME-типа при рендеринге страницы на сервере Node.js:

  • Используйте надежный список MIME-типов. Вы можете найти список MIME-типов на веб-сайте IANA.
  • Проверяйте MIME-тип как можно раньше. Чем раньше вы проверите MIME-тип, тем меньше вероятность того, что вредоносный файл будет обработан.
  • При необходимости используйте дополнительные меры безопасности. Проверка MIME-типа не является единственным способом защиты вашего сервера от атак. Используйте другие меры безопасности, такие как фильтрация IP-адресов и сканирование файлов на наличие вирусов.

mime-types.json

{
  "extensions": {
    "jpg": "image/jpeg",
    "jpeg": "image/jpeg",
    "png": "image/png",
    "gif": "image/gif",
    "svg": "image/svg+xml",
    "mp4": "video/mp4",
    "webm": "video/webm",
    "ogv": "video/ogg",
    "mov": "video/quicktime",
    "mp3": "audio/mpeg",
    "wav": "audio/wav",
    "ogg": "audio/ogg",
    "aac": "audio/aac",
    "txt": "text/plain",
    "rtf": "text/rtf",
    "pdf": "application/pdf",
    "zip": "application/zip",
    "rar": "application/x-rar-compressed",
    "7z": "application/x-7z-compressed",
    "tar": "application/x-tar",
    "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    "doc": "application/msword",
    "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
    "ppt": "application/mspowerpoint",
    "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    "xls": "application/vnd.ms-excel",
    "html": "text/html",
    "css": "text/css",
    "js": "application/javascript",
    "ico": "image/vnd.microsoft.icon"
  }
}

Пример 1.

В этом примере, мы сначала получаем расширение запрашиваемого файла с помощью свойства req.file.name.split(".").pop(). Затем мы используем это расширение для получения MIME-типа из JSON-файла с помощью свойства mimeTypes.extensions[extension]. Наконец, мы устанавливаем MIME-тип с помощью метода res.setHeader().

const express = require("express");

const app = express();

const mimeTypes = require("./mime-types.json");

app.get("/favicon.ico", (req, res) => {
  // Получаем расширение запрашиваемого файла
  const extension = req.file.name.split(".").pop();

  // Получаем MIME-тип из JSON-файла
  const mimeType = mimeTypes.extensions[extension];

  // Устанавливаем MIME-тип
  res.setHeader("Content-Type", mimeType);

  // Отправляем файл
  res.sendFile(req.file);
});

app.listen(3000);

Пример 2.

В этом примере, мы сначала проверяем, есть ли расширение в JSON-файле с помощью метода hasOwnProperty(). Если расширение присутствует, мы получаем MIME-тип из JSON-файла и устанавливаем его. В противном случае, мы отправляем ответ с ошибкой.

const express = require("express");

const app = express();

const mimeTypes = require("./mime-types.json");

app.get("/favicon.ico", (req, res) => {
  // Получаем расширение запрашиваемого файла
  const extension = req.file.name.split(".").pop();

  // Проверяем, есть ли расширение в JSON-файле
  if (mimeTypes.extensions.hasOwnProperty(extension)) {
    // Получаем MIME-тип из JSON-файла
    const mimeType = mimeTypes.extensions[extension];

    // Устанавливаем MIME-тип
    res.setHeader("Content-Type", mimeType);
  } else {
    // Отправляем ответ с ошибкой
    res.sendStatus(400);
  }

  // Отправляем файл
  res.sendFile(req.file);
});

app.listen(3000);

вариант от pi.ai

const express = require('express');

const url = require('url');

const app = express();

const allowedExtensions = ['.jpg', '.png', '.txt', '.html'];

const allowedMimeTypes = ['image/jpeg', 'image/png', 'text/plain', 'text/html'];

app.get('/:filePath', (req, res) => {

  const { pathname, search, hash } = url.parse(req.url);

  const fileExtension = pathname.split('.').pop();

  if (allowedExtensions.includes(fileExtension) && allowedMimeTypes.includes(fileExtensionToMimeTypeMap[fileExtension])) {

    // Serve the file by reading it from disk or from a database.

  } else {

    res.status(404).send('File type not allowed');

  }

});

// Start the server

app.listen(3000)

you.com подсказывает другой способ

проверка mime типа по белому листу

const express = require('express');
const url = require('url');
const app = express();
const fs = require('fs');

app.get('/:filePath', (req, res) => {
  const { filePath } = req.params; // Извлекаем путь к файлу из параметра запроса
  const fileExtension = filePath.split('.').pop();
  
  // Определите MIME-тип на основе расширения файла
  const fileExtensionToMimeTypeMap = {
    'jpg': 'image/jpeg',
    'png': 'image/png',
    'ico': 'image/x-icon',
    'pdf': 'application/pdf'
    // Добавьте другие соответствия по мере необходимости
  };

  if (fileExtensionToMimeTypeMap[fileExtension]) {
    const mimeType = fileExtensionToMimeTypeMap[fileExtension];

    // Установите заголовок Content-Type и отправьте файл в качестве ответа
    res.setHeader('Content-Type', mimeType);
    fs.createReadStream(filePath).pipe(res); // Отправляем файл в качестве ответа
  } else {
    res.status(404).send('File type not allowed');
  }
});

// Start the server
app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

или раскидаем по директориям

const express = require('express');
const app = express();
const fs = require('fs');

app.get('/:fileType/:fileName', (req, res) => {
  const { fileType, fileName } = req.params; // Извлекаем тип файла и имя файла из параметров запроса

  // Определите директорию на основе типа файла
  const directoryPathMap = {
    'images': 'images_directory',
    'pdf': 'pdf_files_directory',
    // Добавьте другие соответствия по мере необходимости
  };

  if (directoryPathMap[fileType]) {
    const filePath = `${directoryPathMap[fileType]}/${fileName}`;
    const fileExtension = fileName.split('.').pop();

    // Определите MIME-тип на основе расширения файла
    const fileExtensionToMimeTypeMap = {
      'jpg': 'image/jpeg',
      'png': 'image/png',
      'ico': 'image/x-icon',
      'pdf': 'application/pdf'
      // Добавьте другие соответствия по мере необходимости
    };

    if (fileExtensionToMimeTypeMap[fileExtension]) {
      const mimeType = fileExtensionToMimeTypeMap[fileExtension];

      // Установите заголовок Content-Type и отправьте файл в качестве ответа
      res.setHeader('Content-Type', mimeType);
      fs.createReadStream(filePath).pipe(res); // Отправляем файл в качестве ответа
    } else {
      res.status(404).send('File type not allowed');
    }
  } else {
    res.status(404).send('File type directory not found');
  }
});

// Start the server
app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

В этом обновленном скрипте мы изменили маршрут запроса на /:fileType/:fileName, чтобы передавать как тип файла, так и имя файла. Затем мы определяем директорию на основе типа файла и используем ее для поиска и отправки файла в качестве ответа.

Каждой директории будет разрешен свой тип файлов.

Модифицируем скрипт следующим образом:

  • img - в этой диреткории будут все виды изображений которые вы используете в проекте ico,svg,png,jpg , директория с файлами документации
  • doc - в этой директории будут файлы документации pdf,txt -другие типы файлов не рекомендую, т.к. файлы могут иметь в себе макросы или в разных редакторах и операционных системах отображаются по-разному, могут нанести вред или просто могут не отобразить информацию у некоторых пользователей.
  • files с типом zip в котором я предоставляю доступ к архивам исполняемых файлов (exe,bat,sh) в явном виде исполняемые файлы размещать не рекомендуется.

Код

const express = require('express');
const app = express();
const fs = require('fs');

// Определите карту соответствия директорий и их наборов типов файлов
const directoryTypesMap = {
  'img': ['ico','jpg', 'png', 'gif'],
  'doc': ['pdf'],
  'files':['zip'],
  'css':['css'],
  'js':['js']
  // Добавьте другие соответствия по мере необходимости
};

app.get('/:directory/:fileName', (req, res) => {
  const { directory, fileName } = req.params; // Извлекаем имя директории и имя файла из параметров запроса

  if (directoryTypesMap[directory]) {
    const fileType = fileName.split('.').pop(); // Определяем тип файла на основе его расширения

    if (directoryTypesMap[directory].includes(fileType)) {
      const filePath = `${directory}/${fileName}`;
      const mimeType = getMimeType(fileType); // Получаем MIME-тип файла

      if (mimeType) {
        res.setHeader('Content-Type', mimeType);
        fs.createReadStream(filePath).pipe(res); // Отправляем файл в качестве ответа
      } else {
        res.status(404).send('Unsupported file type');
      }
    } else {
      res.status(404).send('File type not allowed in this directory');
    }
  } else {
    res.status(404).send('Directory not found');
  }
});

function getMimeType(fileType) {
  // Определите соответствия MIME-типов для типов файлов
  const fileExtensionToMimeTypeMap = {
    'ico': 'image/vnd.microsoft.icon',
	'svg': 'image/svg+xml',
	'jpg': 'image/jpeg',
    'png': 'image/png',
    'gif': 'image/gif',
    'pdf': 'application/pdf',
	'zip': 'application/zip',
	'js':	'text/javascript',
	'css':	'text/css'
    // Добавьте другие соответствия по мере необходимости
  };

  return fileExtensionToMimeTypeMap[fileType];
}

// Start the server
app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

Этот и другой код вы можете легко создать в чате AskCodi ( имеет плагины для различных IDE)

const express = require('express');
const app = express();
const fs = require('fs');

// Определите карту соответствия директорий и их наборов типов файлов
const directoryTypesMap = {
  'img': ['ico', 'jpg', 'png', 'gif'],
  'doc': ['pdf'],
  'files': ['zip']
  // Добавьте другие соответствия по мере необходимости
};

app.get('/:fileName', (req, res) => {
  // Выводим сообщение "not allowed" для файлов без директории
  res.send('not allowed');

});
app.get('/:directory/:fileName', (req, res) => {
  const { directory, fileName } = req.params; // Извлекаем имя директории и имя файла из параметров запроса

  // Добавляем проверку, если директория отсутствует
  if (!directory || directory === '') {
    res.status(404).send('Not allowed');
    return;
  }

  if (directoryTypesMap[directory]) {
    const fileType = fileName.split('.').pop(); // Определяем тип файла на основе его расширения

    if (directoryTypesMap[directory].includes(fileType)) {
      const filePath = `${directory}/${fileName}`;
      const mimeType = getMimeType(fileType); // Получаем MIME-тип файла

      if (mimeType) {
        res.setHeader('Content-Type', mimeType);
        fs.createReadStream(filePath).pipe(res); // Отправляем файл в качестве ответа
      } else {
        res.status(404).send('Unsupported file type');
      }
    } else {
      res.status(404).send('File type not allowed in this directory');
    }
  } else {
    res.status(404).send('Directory not found');
  }
});

function getMimeType(fileType) {
  // Определите соответствия MIME-типов для типов файлов
  const fileExtensionToMimeTypeMap = {
    'ico': 'image/vnd.microsoft.icon',
    'svg': 'image/svg+xml',
    'jpg': 'image/jpeg',
    'png': 'image/png',
    'gif': 'image/gif',
    'pdf': 'application/pdf',
    'zip': 'application/zip'
    // Добавьте другие соответствия по мере необходимости
  };

  return fileExtensionToMimeTypeMap[fileType];
}

// Start the server
app.listen(3000, () => {
  console.log('Server is running on port 3000');
});