# File Upload

## 1. Введение:

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

Одним словом, соблюдение этих правил должно быть достаточным для защиты от любых известных атак, которые могут быть совершены через загрузку файлов:

* [x] Список разрешенных расширений. Разрешите только безопасные и критически важные расширения для бизнес-функций.
* [x] **Убедитесь, что загруженные файлы не могут быть выполнены как код!**
* [x] Убедитесь, что проверка ввода применяется перед проверкой расширений.
* [x] Измените имя файла на то, которое генерируется приложением. (например, пользовательская хэш-функция 'a.txt' -> jd21j3jjd213jj3321.txt)
* [x] Установите ограничение на длину имени файла. По возможности ограничьте допустимые символы. (Попробуйте очистить имя файла)
* [x] Установите ограничение на размер файла.
* [x] Разрешите загрузку файлов только авторизованным пользователям.
* [x] Храните файлы на другом сервере. Если это невозможно, храните их за пределами webroot.
* [x] В случае публичного доступа к файлам используйте обработчик, который сопоставляется с именами файлов внутри приложения (некоторый идентификатор -> файл.расширение)
* [x] Прогоняте файлы через антивирус или "песочницу", если таковая имеется, чтобы убедиться, что он не содержит вредоносных данных.
* [x] Убедитесь, что все используемые библиотеки надежно настроены и поддерживаются в актуальном состоянии.
* [x] Защитите загрузку файла от CSRF-атак. (Если у вас реализовано что-то вроде `get-this-file-from-this-url`).

## 2. Методы смягчения последствий и защиты:

### 2.1. Использование системы безопасного хранения:

`Зомби, которого нет в вашем доме, не может причинить вам вреда!`

Шутки в сторону, один из самых важных подходов к обеспечению безопасности функции загрузки файлов заключается в том, чтобы ваш веб-сервер воспринимал загружаемые файлы как инертные, а не как исполняемые объекты. В этом смысле вы можете выбрать альтернативу хранения загружаемых файлов в CDN (Content Delivery Network), например Cloudflare; возможно, вы уже догадались из моей цитаты про зомби, что таким образом разработчик, по сути, снимает бремя безопасности с третьей стороны, с которой он работает, так что файлы всегда хранятся безопасно таким образом.

Конечно, использование CDN может оказаться не самым лучшим вариантом, и тогда вы можете выбрать одну из других альтернатив, например облачное хранилище (Amazon S3, Google Storage Bucket и т. д.) или даже выделенную CMS (хотя это сопряжено с дополнительной головной болью по настройке и вниманию).

### 2.2. Различные методы защиты и альтернативы:

Вы можете не использовать CDN или любую из перечисленных выше альтернатив. В таком случае, если вам действительно необходимо загрузить файлы на "локальный" диск, вот что нужно сделать:

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

{% tabs %}
{% tab title="Python" %}

```python
import os

file_f = os.open("/path/to/your/file", os.O_WRONLY | os.O_CREAT, 0o600)

with os.fdopen(open(file_f, "wb")) as file_handling:
    file_handling.write(...)
```

{% endtab %}

{% tab title="Node.js" %}

```ruby
var chmodr = require('chmodr');

chmodr('/path/to/entire/folder', 0o600, (err) => {
  if (err) {
    console.log('Failed to execute chmod', err);
  } else {
    console.log('Success');
  }
});

```

{% endtab %}
{% endtabs %}

* Проверка расширений файлов: убедитесь, что проверка происходит после декодирования имени файла и что установлен соответствующий фильтр, чтобы избежать некоторых известных обходов, таких как следующие:
  * Двойные расширения, например .jpg.php, где легко обходится regex .jpg.
  * Нулевые байты, например, .php%00.jpg, где .jpg обрезается, а .php становится новым расширением.
  * Плохой регекс, который не был должным образом протестирован и проверен. Воздержитесь от создания собственной логики, если у вас нет достаточных знаний по этой теме.
* Проверка содержимого файла: Поскольку содержимое файла может содержать вредоносные или нежелательные данные, разработчик всегда может провести его дополнительную проверку, основываясь на предполагаемом типе файла:
  * Что касается изображений, то стоит прочитать эти два поста: Inject Executable, malicious code into PNG и How can I be protected from picture vulnerabilities. Переписывание изображений - одна из распространенных техник, которая теоретически уничтожает любой вид вредоносного содержимого, которое может быть внедрено в изображение, и обычно это делается с помощью рандомизации.
  * Загружать ZIP-файлы категорически не рекомендуется, поскольку они могут содержать буквально любые типы файлов, а значит, допускают безграничные возможности.

## 3. Выводы:

Хотя фундаментальные аспекты загрузки файлов остаются неизменными, разработчики не без оснований начали искать способы "встраивания" систем хранения файлов, которые были бы простыми, безопасными и в целом удобными в использовании.
