Espruino:Примеры/Безопасность и контроль доступа при использовании BLE на Puck.js

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Безопасность и контроль доступа при использовании BLE на Puck.js[1]

В момент, когда вы вынете пластиковый разделитель из батарейного отсека Puck.js, устройство тут же запустится, после чего к нему можно будет подключиться и программировать.

Как и прочие подобные устройства для разработки проектов, Puck.js создан с прицелом на то, чтобы вы могли начать пользоваться им как можно быстрее – без необходимости вводить пароли.

Но как только вы возьмётесь за более-менее серьёзные проекты, то наверняка захотите поставить защиту, чтобы Puck.js не мог перепрограммировать кто-то другой.

Примечание

Если в Puck.js не будет настроена привязка (см. раздел «Привязка и белый список» ниже), Bluetooth-коммуникация будет незашифрованной. В этом случае будьте готовы к тому, что рядом может оказаться злоумышленник с устройством для прослушки Bluetooth-связи, который сможет просматривать всё, что было записано и загружено на Puck.js.

Итак, как же защитить Puck.js? Есть несколько вариантов.

Запретите подключаться к Puck.js

При помощи функции NRF.setAdvertising() вы можете разрешить Puck.js рассылать Bluetooth-объявления, но также сделать так, чтобы к нему не мог подключиться ни один ПК:

NRF.setAdvertising({}, { connectable:false });

Поставьте пароль при помощи E.setPassword("пароль")

См. тут. В результате UART продолжить работать, и любой компьютер по-прежнему сможет подключиться к Puck.js, но теперь каждый, кто захочет получить доступ к консоли Espruino, должен будет ввести пароль.

Это неидеальный вариант, так как к Puck.js по-прежнему сможет подключиться любой – он просто не получит доступа к JavaScript-консоли.

Спрячьте консоль

При помощи команды LoopbackA.setConsole(true) можно принудительно поместить JavaScript-консоль в Loopback.

В результате консоль будет доступна только через чтение и запись в переменную LoopbackB. Если кто-то подключится к Puck.js, у него по-прежнему будет доступ к UART, но он ничего не сможет сделать.

Всё, что будет записываться в Bluetooth UART, по-прежнему будет доступно в переменной Bluetooth через Bluetooth.on('data', function(data) { ... }), и вы также сможете отправлять ответы при помощи Bluetooth.write(...).

Примечание

Вы больше не сможете программировать Puck.js, пока не выполните сброс или не вызовите Bluetooth.setConsole().

Отключение при обнаружении незнакомого адреса (белый список)

Вы можете легко подцепиться к событию connect, а затем принудительно отключиться, если обнаружится, что подключение инициировано незнакомым адресом.

NRF.on('connect',function(addr) {
  if (addr!="69:2d:94:d0:9d:97 public")
    NRF.disconnect();
});

У других Puck.js адрес обычно имеет формат "aa:bb:cc:dd:ee:ff random", а у ПК и телефонов это, как правило, что-то вроде "aa:bb:cc:dd:ee:ff public".

Чтобы выяснить, какой MAC-адрес добавить в белый список, загрузите вот этот код:

devices = [];
NRF.on('connect',function(addr) {
  devices.push(addr);
});
// теперь подключитесь несколько раз
// и посмотрите, что находится в «devices» в левой части IDE
Примечание

Новые версии Android умеют делать «рандомизацию MAC-адреса» – это позволяет им при каждом новом подключении использовать случайный MAC-адрес. В таком случае этот метод не подойдёт.

Примечание

MAC-адреса можно менять, так что этот метод надёжен не на 100%. Впрочем, шансы на то, что кто-то угадает правильный MAC-адрес – не находясь при этом в области подключения в момент, когда соединение активно, чтобы иметь возможность его прослушать – крайне малы.

Отключите BLE UART

Если вы не хотите, чтобы у пользователя был доступ к BLE UART, рекомендуем полностью его отключить при помощи NRF.setServices().

NRF.setServices(undefined, {
  uart : false
});

Это полностью отключит сервис UART, в результате чего Puck.js нельзя будет перепрограммировать (пока не выполнить сброс).

Если снова вызвать NRF.setServices() с настройкой uart:true, это возобновит работу UART. К примеру, код ниже выключает и включает UART (а также мигает красным и зелёным светодиодами) при нажатии на кнопку.

var locked = true;
NRF.setServices(undefined,{uart:!locked}­);
setWatch(function() {
  locked = !locked;
  digitalPulse(locked?LED1:LED2,1,100);
  NRF.setServices(undefined,{uart:!locked}­);
}, BTN, {repeat:true, edge:"rising", debounce:50});

Отключите Bluetooth

Вы можете включить и выключить Bluetooth при помощи функций NRF.sleep() и NRF.wake().

Это остановит рассылку Bluetooth-объявлений, с помощью которых Puck.js объявляет о своём присутствии, а также сделает так, чтобы к Puck.js нельзя было подключиться. Это также увеличит продолжительность работы батареи.

Код ниже мигает красным и зелёным светодиодами, а также включает и выключает Bluetooth.

var locked = false;
setWatch(function() {
  locked = !locked;
  digitalPulse(locked?LED1:LED2,1,100);
  if (locked) NRF.sleep();
  else NRF.wake();
}, BTN, {repeat:true, edge:"rising", debounce:50});

Привязка / занесение в белый список

В версии Espruino 1v92 в Puck.js была реализована функция привязки. Будучи привязанными, устройства могут создавать безопасное подключение друг к другу.

Puck.js принимает и безопасные, и небезопасные подключения – решение о том, запускать ли процедуру привязки или нет, остаётся за подключающимся устройством. Если вызвать функцию NRF.setWhitelist(true), то следующее устройство, которое будет привязано к Puck.js, будет также добавлено в белый список. В результате устройства, которых нет в белом списке, к Puck.js подключиться не смогут, пока он не будет перезапущен (для этого нужно зажать кнопку).

Сам Puck.js, подключаясь к другому устройству, тоже может инициировать процедуру привязки – это делается с помощью метода startBonding(). Кроме того, подключившись, при помощи функции getSecurityStatus() можно узнать настройки безопасности соединения.

Сопряжение с помощью ключа доступа (пароля)

В версии Espruino 2v02 (и в самых свежих, но нестабильных билдах) можно задать статический ключ доступа (пароль).

NRF.setSecurity({passkey:"123456", mitm:1, display:1});

При попытке подключения центральное устройство запросит ключ доступа (пароль), и если он окажется неправильным, подключение установлено не будет.

Когда Espruino работает в режиме центрального устройства, которому нужно подключиться к другому устройству, ключ доступа можно ввести при помощи события BluetoothDevice.passkeyRequest и метода BluetoothDevice.sendPasskey() но при этом в NRF.setSecurity должно быть задано keyboard:1).

Отключите команды dump() и E.dumpStr()

Благодаря этим командам тот, у кого есть доступ к консоли Espruino, может легко выгрузить программный код, хранящийся на устройстве.

Их можно отключить при помощи global.dump=function(){};E.dumpStr=function(){};, но полную защиту это не гарантирует, потому что, выполнив некоторые манипуляции, их можно снова включить. Кроме того, если злоумышленник будет иметь доступ к консоли Espruino, то сможет прочесть состояние интерпретатора даже без этих команд. Другими словами, вы можете реконструировать большую часть кода, даже не используя dump().

Если вас беспокоит то, что кто-то может прочесть ваш код, лучше вообще отключите консоль (см. выше).

См.также

Внешние ссылки