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().

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

См.также

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