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

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску
Нет описания правки
Нет описания правки
Строка 11: Строка 11:
Но как только вы возьмётесь за более-менее серьёзные проекты, то наверняка захотите поставить защиту, чтобы [[Puck.js]] не мог перепрограммировать кто-то другой.
Но как только вы возьмётесь за более-менее серьёзные проекты, то наверняка захотите поставить защиту, чтобы [[Puck.js]] не мог перепрограммировать кто-то другой.


'''Примечание:''' Если в [[Puck.js]] не будет настроена привязка (см. раздел «Привязка и белый список» ниже), Bluetooth-коммуникация будет незашифрованной. В этом случае будьте готовы к тому, что рядом может оказаться злоумышленник с устройством для прослушки Bluetooth-связи, который сможет просматривать всё, что было записано и загружено на Puck.js.
'''Примечание:''' Если в [[Puck.js]] не будет настроена привязка (см. раздел [http://wikihandbk.com/wiki/Espruino:%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B/%D0%91%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%B8_%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D1%8C_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%B0_%D0%BF%D1%80%D0%B8_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B8_BLE_%D0%BD%D0%B0_Puck.js#.D0.9F.D1.80.D0.B8.D0.B2.D1.8F.D0.B7.D0.BA.D0.B0_.2F_.D0.B7.D0.B0.D0.BD.D0.B5.D1.81.D0.B5.D0.BD.D0.B8.D0.B5_.D0.B2_.D0.B1.D0.B5.D0.BB.D1.8B.D0.B9_.D1.81.D0.BF.D0.B8.D1.81.D0.BE.D0.BA «Привязка и белый список»] ниже), Bluetooth-коммуникация будет незашифрованной. В этом случае будьте готовы к тому, что рядом может оказаться злоумышленник с устройством для прослушки Bluetooth-связи, который сможет просматривать всё, что было записано и загружено на [[Puck.js]].


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


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


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


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 25: Строка 25:
== Поставьте пароль при помощи E.setPassword("пароль") ==
== Поставьте пароль при помощи E.setPassword("пароль") ==


[http://wikihandbk.com/wiki/Espruino:Справочник_по_API/Класс_E/setPassword() См. тут]. В результате UART продолжить работать, и любой компьютер по-прежнему сможет подключиться к Puck.js, но теперь каждый, кто захочет получить доступ к консоли Espruino, должен будет ввести пароль.
[[Espruino:Справочник_по_API/Класс_E/setPassword()|См. тут]]. В результате [[UART]] продолжить работать, и любой компьютер по-прежнему сможет подключиться к [[Puck.js]], но теперь каждый, кто захочет получить доступ к консоли [[Espruino]], должен будет ввести пароль.


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


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


При помощи команды LoopbackA.setConsole(true) можно принудительно поместить JavaScript-консоль в [http://wikihandbk.com/wiki/Espruino:Справочник_по_API/Глобальные_методы,_переменные_и_объекты/Объект_LoopBackA Loopback].
При помощи команды LoopbackA.setConsole(true) можно принудительно поместить [[JavaScript-консоль]] в [[Espruino:Справочник_по_API/Глобальные_методы,_переменные_и_объекты/Объект_LoopBackA|Loopback]].


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


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


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


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


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


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 50: Строка 50:
</syntaxhighlight>
</syntaxhighlight>


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


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


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 63: Строка 63:
</syntaxhighlight>
</syntaxhighlight>


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


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


== Отключите BLE UART ==
== Отключите BLE UART ==


Если вы не хотите, чтобы у пользователя был доступ к BLE UART, рекомендуем полностью его отключить при помощи [http://wikihandbk.com/wiki/Espruino:Справочник_по_API/Класс_NRF/setServices() NRF.setServices()].
Если вы не хотите, чтобы у пользователя был доступ к [[BLE UART]], рекомендуем полностью его отключить при помощи [[Espruino:Справочник_по_API/Класс_NRF/setServices()|NRF.setServices()]].


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 77: Строка 77:
</syntaxhighlight>
</syntaxhighlight>


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


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


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 93: Строка 93:
== Отключите Bluetooth ==
== Отключите Bluetooth ==


Вы можете включить и выключить Bluetooth при помощи функций [http://wikihandbk.com/wiki/Espruino:Справочник_по_API/Класс_NRF/sleep() NRF.sleep()] и [http://wikihandbk.com/wiki/Espruino:Справочник_по_API/Класс_NRF/wake() NRF.wake()].
Вы можете включить и выключить [[Bluetooth]] при помощи функций [[Espruino:Справочник_по_API/Класс_NRF/sleep()|NRF.sleep()]] и [[Espruino:Справочник_по_API/Класс_NRF/wake()|NRF.wake()]].


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


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


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 111: Строка 111:
== Привязка / занесение в белый список ==
== Привязка / занесение в белый список ==


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


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


Сам Puck.js, подключаясь к другому устройству, тоже может инициировать процедуру привязки – это делается с помощью метода startBonding(). Кроме того, подключившись, при помощи функции [http://wikihandbk.com/wiki/Espruino:Справочник_по_API/Класс_BluetoothRemoteGATTServer/getSecurityStatus() getSecurityStatus() можно узнать настройки безопасности соединения].
Сам [[Puck.js]], подключаясь к другому устройству, тоже может инициировать процедуру привязки – это делается с помощью метода startBonding(). Кроме того, подключившись, при помощи функции [[Espruino:Справочник_по_API/Класс_BluetoothRemoteGATTServer/getSecurityStatus()|getSecurityStatus() можно узнать настройки безопасности соединения]].


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


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


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript" enclose="div">
Строка 127: Строка 127:
При попытке подключения центральное устройство запросит ключ доступа (пароль), и если он окажется неправильным, подключение установлено не будет.  
При попытке подключения центральное устройство запросит ключ доступа (пароль), и если он окажется неправильным, подключение установлено не будет.  


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


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


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


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


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

Версия от 15:39, 6 марта 2021

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


Безопасность и контроль доступа при использовании 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().

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

См.также

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