Принципы практической безопасности в IoT-системах
COURSE-16-M04-L02 — Принципы практической безопасности в IoT-системах
Введение в практическую безопасность
Безопасность в системах Интернета вещей (IoT) — это не опция, а фундаментальное требование. Любое устройство, подключенное к сети, является потенциальной точкой входа для злоумышленников. Цель данного урока — не просто перечислить теоретические принципы, а дать инженерам HI конкретные, воспроизводимые инструкции по их применению на нашей платформе. Мы рассмотрим, как превратить абстрактные концепции безопасности в работающие конфигурации на контроллере HI, используя его встроенные возможности: ОС Debian, среду Node-RED и стандартные протоколы.
Каждый принцип будет рассмотрен через призму практической реализации. Ваша задача как инженера — не просто внедрить систему, а сделать ее устойчивой к внешним и внутренним угрозам.
Принцип 1: Безопасность по умолчанию (Security by Default)
Описание: Любое устройство или приложение должно быть сконфигурировано с максимальным уровнем безопасности "из коробки". Нельзя полагаться на то, что конечный пользователь или инженер самостоятельно выполнит базовые настройки защиты. Платформа HI поставляется с преднастроенной средой, но ее необходимо финализировать на объекте. Практическая реализация на платформе HI:* Доступ по SSH к ОС Debian: Сразу после первого входа в систему смените пароль пользователя `admin` (или другого стандартного пользователя).
# Подключитесь к контроллеру по SSH
ssh admin@
# Немедленно выполните команду смены пароля
passwd
# Следуйте инструкциям для ввода нового, сложного пароля
* Доступ к редактору Node-RED: Защитите веб-интерфейс Node-RED, который является основным инструментом управления логикой.
* Отредактируйте файл конфигурации `settings.js`:
sudo nano /home/admin/.node-red/settings.js
* Найдите и раскомментируйте секцию `adminAuth`. Замените стандартные значения на ваши. Для генерации хеша пароля используйте утилиту `node-red-admin hash-pw`.
// Пример секции adminAuth в settings.js
adminAuth: {
type: "credentials",
users: [{
username: "hi-engineer",
password: "$2a$08$z...ва...ш...сгенерированный...хеш...пароля...",
permissions: "*"
}]
},
* Доступ к MQTT-брокеру: Если на контроллере используется локальный брокер Mosquitto, настройте аутентификацию по логину и паролю.
* Для защиты веб-интерфейса Node-RED рекомендуется включить HTTPS. Это требует наличия SSL-сертификатов и рассматривается в курсе уровня `Integration`, но вы должны знать о такой возможности.
💡 Совет: Создайте "золотой образ" (golden image) контроллера с уже выполненными базовыми настройками безопасности. Это позволит быстро разворачивать новые защищенные контроллеры на типовых объектах.
Принцип 2: Минимизация поверхности атаки
Описание: Поверхность атаки — это совокупность всех возможных точек (векторов), через которые злоумышленник может попытаться атаковать систему. Наша задача — сократить эту поверхность до абсолютного минимума, оставив только те сервисы, порты и протоколы, которые необходимы для работы системы. Практическая реализация на платформе HI:
# Пример: если Bluetooth не используется, отключаем и деактивируем службу
sudo systemctl stop bluetooth.service
sudo systemctl disable bluetooth.service
Проверьте другие службы, такие как `cups` (печать), `avahi-daemon` (сетевое обнаружение), если они не требуются для вашего проекта.
# Установка (если не установлен)
sudo apt install ufw
# 1. Запрещаем все входящие и разрешаем все исходящие соединения по умолчанию
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 2. Разрешаем только необходимые порты
sudo ufw allow 22/tcp # SSH (для управления)
sudo ufw allow 1880/tcp # Node-RED UI
sudo ufw allow 1883/tcp # MQTT
# sudo ufw allow 502/tcp # Modbus TCP (если используется)
# 3. Включаем брандмауэр
sudo ufw enable
# 4. Проверяем статус
sudo ufw status verbose
⚠️ Предупреждение: Никогда не "пробрасывайте" порты контроллера (SSH, Node-RED) напрямую в интернет через настройки роутера (Port Forwarding) без использования VPN. Это открывает прямой доступ к вашей системе из любой точки мира.
Принцип 3: Аутентификация и Авторизация
Описание: Это два разных, но связанных понятия.- Аутентификация: Проверка того, что субъект (пользователь, другое устройство) является тем, за кого себя выдает. (Ответ на вопрос "Кто ты?").
- Авторизация: Проверка того, имеет ли аутентифицированный субъект право на выполнение определенного действия. (Ответ на вопрос "Что тебе можно делать?").
* MQTT: Всегда используйте аутентификацию по логину и паролю. В узлах `mqtt in` и `mqtt out` в Node-RED обязательно настраивайте сервер с указанием имени пользователя и пароля.
* HTTP API: Если вы создаете HTTP-эндпоинты с помощью узлов `http in`, реализуйте проверку токена доступа в заголовке запроса.
Создайте централизованный субпоток для проверки прав доступа. Это классический пример паттерна Конечный автомат (FSM), где состояние — это уровень доступа.
Сценарий: Управление освещением через MQTT. Команды приходят в топик `hi/commands/light`. Только пользователи с ролью `admin` или `user` могут управлять светом.
* Контракт сообщения:
// msg.payload от внешнего клиента
{
"command": "ON",
"target": "RL-01",
"user_token": "a1b2c3d4e5f6" // Токен, идентифицирующий пользователя
}
* ASCII-схема потока авторизации:
[MQTT In: hi/commands/#] -> [Function: Check ACL] --+-- (Доступ разрешен) -> [Switch: route command] -> [Управление реле]
|
+-- (Доступ запрещен) -> [Function: Log Denied] -> [MQTT Out: audit/log]
* Код для узла `Function: Check ACL`:
// Список контроля доступа (ACL). В реальной системе он может храниться
// в файле, базе данных MySQL или в защищенном контексте.
const acl = {
"a1b2c3d4e5f6": { username: "main_user", role: "user" },
"f6e5d4c3b2a1": { username: "admin", role: "admin" }
};
const token = msg.payload.user_token;
if (token && acl[token]) {
const user = acl[token];
// Проверяем, есть ли у пользователя право на это действие
if (user.role === 'admin' || user.role === 'user') {
node.status({ fill: "green", shape: "dot", text: `OK: ${user.username}` });
// Добавляем информацию о пользователе в сообщение для аудита
msg.auth_info = user;
return msg; // Отправляем на первый выход (успех)
}
}
node.status({ fill: "red", shape: "dot", text: "Access Denied" });
// Формируем сообщение для лога безопасности
msg.audit_log = {
ts: Date.now(),
event: "ACCESS_DENIED",
source_ip: msg.req.ip, // Если используется HTTP In
token: token,
target: msg.payload.target
};
return [null, msg]; // Отправляем на второй выход (отказ)
Принцип 4: Шифрование данных
Описание: Данные уязвимы в двух состояниях: "в пути" (in-transit), когда они передаются по сети, и "в состоянии покоя" (at-rest), когда они хранятся на устройстве. Оба состояния требуют защиты. Практическая реализация на платформе HI:* TLS для MQTT: Настройте ваш MQTT-брокер и клиенты в Node-RED на использование шифрования TLS. Это превращает `mqtt://` в `mqtts://`. Это предотвращает перехват и чтение трафика в локальной сети.
* HTTPS для Node-RED: Как упоминалось ранее, включите HTTPS для доступа к редактору.
* ⚠️ Modbus RTU/DALI/CAN: Помните, что промышленные шины, такие как RS-485, CAN и DALI, не поддерживают шифрование на уровне протокола. Это делает критически важной физическую безопасность кабельных трасс. Используйте рекомендации из стандарта `WIRING-SENS-004`.
* Конфиденциальные данные в Node-RED: Никогда не храните пароли, API-ключи или токены в виде простого текста в узлах `Function` или `Change`. Используйте переменные окружения (`process.env.MY_API_KEY`) или механизм `Credentials` в узлах конфигурации.
* База данных MySQL: Если вы храните чувствительные данные в локальной БД MySQL, используйте встроенные функции шифрования MySQL для защиты полей.
Принцип 5: Управление обновлениями и уязвимостями
Описание: Ни одно ПО не является на 100% безопасным. Постоянно обнаруживаются новые уязвимости. Единственный способ защиты — это своевременное применение обновлений безопасности для операционной системы, среды исполнения и библиотек. Практическая реализация на платформе HI:
# Обновить список пакетов и установить обновления
sudo apt update && sudo apt upgrade -y
* Следите за выходом новых версий Node-RED.
* Периодически проверяйте наличие обновлений для установленных палитр через `Menu -> Manage Palette`. Устаревшие узлы могут содержать уязвимости.
📋 Чек-лист ежемесячного обслуживания безопасности:
- [ ] Подключиться к контроллеру по SSH.
- [ ] Выполнить `sudo apt update && sudo apt upgrade -y`.
- [ ] Перезагрузить контроллер, если было обновлено ядро (`sudo reboot`).
- [ ] Открыть редактор Node-RED.
- [ ] Проверить и установить обновления для палитр в `Manage Palette`.
- [ ] Проверить системные логи на наличие подозрительной активности.
Принцип 6: Мониторинг, аудит и реагирование
Описание: Невозможно защититься от всех атак, но можно и нужно обнаруживать их как можно раньше. Система должна непрерывно вести журнал всех важных событий (особенно связанных с безопасностью) и иметь механизмы для оповещения о подозрительной активности. Практическая реализация на платформе HI:Это прямая реализация паттернов Node-RED "Обработка ошибок" и "Визуальный статус".
* Используйте узел `Catch` на каждой вкладке для перехвата всех ошибок.
* Направьте все ошибки и события безопасности (например, "Доступ запрещен" из Принципа 3) в единый поток для журналирования.
Этот поток будет принимать события и записывать их в базу данных MySQL на контроллере.
* Структура таблицы `audit_log` в MySQL:
CREATE TABLE `audit_log` (
`id` INT NOT NULL AUTO_INCREMENT,
`ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`event_type` VARCHAR(50) NOT NULL,
`source` VARCHAR(100),
`username` VARCHAR(50),
`details` JSON,
PRIMARY KEY (`id`)
);
* ASCII-схема потока аудита:
[Link In: from all flows] -> [Function: Format Log] -> [MySQL Node] -> [Debug: Log OK]
* Код для узла `Function: Format Log`:
// Пример входящего msg из потока авторизации
// msg.audit_log = { event: "ACCESS_DENIED", ... }
const log = msg.audit_log || msg.payload; // Гибкость
const event_type = log.event || "GENERIC_ERROR";
const source = msg.error ? msg.error.source.name : (log.source || "Unknown");
const username = msg.auth_info ? msg.auth_info.username : "system";
// Формируем SQL-запрос
msg.topic = `INSERT INTO audit_log (event_type, source, username, details) VALUES (?, ?, ?, ?)`;
msg.payload = [
event_type,
source,
username,
JSON.stringify(log) // Сохраняем все детали в формате JSON
];
return msg;
---
Лабораторные работы
COURSE-16-M04-LAB03: Базовая защита контроллера HI ("Закалка")
Цель: Выполнить первичную, самую важную настройку безопасности нового контроллера. Оборудование: Контроллер HI, компьютер с SSH-клиентом. Пошаговое руководство:- [ ] Пароль SSH изменен. (Проверяется попыткой входа со старым паролем).
- [ ] Веб-интерфейс Node-RED защищен паролем. (Проверяется в браузере).
- [ ] `ufw` активен и настроен корректно. (Проверяется командой `sudo ufw status`).
COURSE-16-M04-LAB04: Создание потока аудита и авторизации
Цель: Реализовать в Node-RED логику проверки прав доступа и журналирования событий безопасности в базу данных MySQL. Оборудование: Контроллер HI с настроенной MySQL и `node-red-contrib-db-mysql`. Пошаговое руководство:- Реализуйте временную блокировку пользователя после 3 неудачных попыток авторизации.
- Разделите права: `user` может только включать/выключать свет, а `admin` может еще и менять яркость (другая команда).
- [ ] Поток авторизации корректно разделяет легитимные и нелегитимные команды.
- [ ] При отказе в доступе в консоли Node-RED не возникает ошибок.
- [ ] В таблице `audit_log` создается корректная запись о событии `ACCESS_DENIED`.
- [ ] Поток использует паттерн "Контракт сообщения" для команд.
---
Тест для самопроверки (Квиз)
ID: `COURSE-16-M04-QUIZ`a) Настроить MQTT-брокер
b) Сменить пароли по умолчанию (SSH, Node-RED)
c) Установить обновления `apt upgrade`
d) Настроить DALI-шину
a) `firewall-cmd`
b) `iptables`
c) `ufw`
d) `netsh`
a) Процесс проверки, кем является пользователь.
b) Процесс проверки, какие действия разрешены пользователю.
c) Процесс шифрования данных.
d) Процесс обновления ПО.
a) `Switch`
b) `Status`
c) `Catch`
d) `Link In`
a) Это замедляет работу потока.
b) Любой, кто имеет доступ к редактору Node-RED, может их увидеть.
c) Это нарушает контракт сообщения.
d) Это может привести к ошибке компиляции.
a) HTTPS
b) MQTTS
c) Modbus RTU (RS-485)
d) SSH
a) Количество реле на контроллере.
b) Совокупность всех потенциальных векторов для атаки на систему.
c) Длина кабеля RS-485.
d) Количество записей в логе аудита.
a) Для хеширования пароля для `settings.js`, чтобы не хранить его в открытом виде.
b) Для шифрования потоков Node-RED.
c) Для смены пароля SSH.
d) Для установки новых узлов.
a) `mosquitto.conf`
b) `/etc/ssh/sshd_config`
c) `package.json`
d) `settings.js`
a) Временная метка события.
b) Тип события (например, `ACCESS_DENIED`).
c) IP-адрес источника.
d) Температура процессора контроллера.
Ответы: 1-b, 2-c, 3-b, 4-c, 5-b, 6-c, 7-b, 8-a, 9-d, 10-d---
Мини-runbook "Если что-то пошло не так"
Симптом: Не могу подключиться к контроллеру по SSH после смены пароля.- Возможная причина: Опечатка при вводе нового пароля. Неправильная раскладка клавиатуры.
- Действия: Попробуйте ввести пароль еще раз, внимательно проверяя символы. Если доступ утерян полностью, может потребоваться физический доступ к контроллеру для сброса пароля через recovery-режим (процедура уровня `Installer`).
- Возможная причина: Синтаксическая ошибка в файле (пропущена запятая, скобка).
- Действия: Проверьте логи Node-RED командой `sudo journalctl -f -u nodered.service`. В логе будет указана строка с ошибкой в файле `settings.js`. Исправьте ошибку и перезапустите службу.
- Возможная причина: Ошибка в логике узла `Function: Check ACL`. Неправильный формат `msg.payload`. ACL-список не содержит нужного токена.
- Действия: Подключите узел `Debug` ко входу узла `Function: Check ACL` и установите его в режим "display the complete msg object". Проверьте, что структура входящего сообщения соответствует той, что вы ожидаете в коде. Проверьте, что токен в сообщении точно совпадает с ключом в объекте `acl`.