npm package: @necrobox/webpack-dev-server-firewall
Description: Firewall for webpack-dev-server
Author: Igor Adamenko
Latest version: 4.0.0

# @necrobox/webpack-dev-server-firewall

[![npm](https://img.shields.io/npm/v/@necrobox/webpack-dev-server-firewall.svg)](https://www.npmjs.com/package/@necrobox/webpack-dev-server-firewall)

Пакет предотвращает неконтролируемый доступ к серверу разработки, 
запрашивая подтверждение при подключении с незнакомого IP.

## Установка

```bash
npm install --save-dev @necrobox/webpack-dev-server-firewall
```

## Использование

Для того чтобы пакет начал работать, необходимо подключить его в конфиге Вебпака, в разделе 
`devServer.setupMiddlewares`:

```js
const firewall = require('@necrobox/webpack-dev-server-firewall');

module.exports = {
  // ...
  devServer: {
    // ...
    setupMiddlewares: (middlewares, devServer) => {
      firewall(devServer);
      // ...
      return middlewares;
    },
  },
};
```

С более старыми версиями webpack-dev-server нужно использовать:

- `devServer.onBeforeSetupMiddleware` для [<4.7.0](https://github.com/webpack/webpack-dev-server/releases/tag/v4.7.0);
- `devServer.before` для [<4.0.0](https://github.com/webpack/webpack-dev-server/releases/tag/v4.0.0);
- `devServer.setup` для [<2.9.0](https://github.com/webpack/webpack-dev-server/releases/tag/v2.9.0).

Функция `firewall` ожидает [Express application](https://expressjs.com/en/4x/api.html#app) в качестве аргумента.

Важно подключать `firewall` до всех остальных обработчиков.

## Механизм работы

По умолчанию пакет пропускает только запросы с `127.0.0.1`.
Если возникает запрос с иного IP, обработчик запрашивает подтверждение в терминале, где запущен webpack-dev-server:

```text
Child serviceworker-plugin:
     1 asset
    Entrypoint undefined = sw.js
    [./src/app/sw.js] 2.82 KiB {0} [built]
ℹ ｢wdm｣: Compiled with warnings.
# ↑ там лог webpack
192.168.1.46 is trying to get access to the server. Allow? [yes / no]:
``` 

Если пользователь соглашается на подключение, IP добавляется в список разрешённых,
и все последующие подключения с него будут разрешены:

```text
192.168.1.46 has been added to known hosts.
``` 

Если пользователь запрещает подключение, клиент, с которого пришёл запрос, 
получает ответ с кодом 403.

### Важные детали

1. Пакет **не** работает как фильтр нежелательных соединений. 
   
   Если пользователь запретил соединение однажды, это не значит, 
   что оно будет игнорироваться и дальше. При повторном подключении с этого IP 
   пакет снова выдаст предупреждение и запросит подтверждение.
   
   Это сделано затем, чтобы разработчик был в курсе всех подозрительных попыток доступа к серверу. 
   
2. Пакет **не** гарантирует полную защиту от злоумышленников.

   Поскольку он никак не проверяет, что IP, с которого приходит новый запрос,
   принадлежит той же машине, с которой когда-то пришёл подтверждённый запрос,
   из этого следует, что при изменении настроек DHCP (или легче: при подключении к другой сети)
   правила, по которым выдавались IP-адреса в локальной сети могут измениться,
   из-за чего ранее подтвеждённый адрес может достаться новой машине, с которой 
   и будут совершены запросы злоумышленником.
   
   Для пущей безопасности можно очищать список разрешённых IP при каждом запуске сервера.
   См. раздел «[Дополнительные функции](#дополнительные-функции)».
   
3. Список разрешённых адресов хранится в `~/.necrobox_webpack_known_hosts`.

   Если необходимо удалить оттуда какой-то конкретный адрес, можно сделать это вручную.
   
   Помимо прочего это означает, что список разрешённых IP один на все проекты, 
   запускаемые на конкретной машине.
   
4. Во избежание ошибок пакет ожидает в качестве подтверждения чёткий ответ `yes`.

   Короткий ответ вроде `y` недопустим. Любой ответ кроме `yes` приравнивается к `no`.

## Дополнительные функции

### CLI

У пакета есть небольшой консольный интерфейс, который позволяет очистить список разрешённых IP:

```bash
webpack-dev-server-firewall forget-known-hosts
```

Важно заметить, что при запуске сервера список разрешённых IP выгружается из файла и хранится в оперативной памяти.
Потому выполнять эту команду нужно после остановки сервера, 
так как иначе файл может быть перезаписан инстансом фаерволла. 

### Методы

Помимо `onBeforeSetupMiddleware`-хука пакет также экспортирует метод `forgetKnownHosts` для вызова функции очистки 
списка разрешённых IP из JS-скрипта. 

Например, при таком описании конфига для Вебпака список IP будет очищаться при каждом запуске сервера:

```js
const firewall = require('@necrobox/webpack-dev-server-firewall');

firewall.forgetKnownHosts();

module.exports = {
  // ...
  devServer: {
    // ...
    onBeforeSetupMiddleware: firewall,
  },
};
```

## Мотивация

Когда разработчики запускают webpack-dev-server на локальной машине, им порой нужно проверить результат работы
с каких-то ещё устройств (например, со смартфонов или планшетов). По умолчанию это сложно сделать,
потому что сервер поднят на `127.0.0.1` и недоступен для соединения с других компьютеров.

Чаще всего для решения этой проблемы разработчики переподнимают сервер на `0.0.0.0` (устанавливая опцию `host`
в конфиге Вебпака), тем самым делая доступным сервер в локальной сети для других устройств. Но в то же время
это позволяет любому пользователю из той же сети получить доступ к серверу, увидеть проект и украсть код. А поскольку
чаще всего дев-сервера раздают ещё и соурс-мапы, то кто угодно может увидеть весь исходный код.

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

Этот фаерволл предотвращает несогласованный доступ к серверу. Он перехватывает все входящие соединения,
сверяет их IP со списком разрешённых и пропускает или отклоняет запросы, в зависимости от результата проверки.