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

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


'''Примечание:''' Если в [[Puck.js]] не будет настроена привязка (см. раздел «Привязка и белый список» ниже), Bluetooth-коммуникация будет незашифрованной. В этом случае будьте готовы к тому, что рядом может оказаться злоумышленник с устройством для прослушки Bluetooth-связи, который сможет просматривать всё, что было записано и загружено на Puck.js.
{{Примечание1|Если в [[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">
NRF.setAdvertising({}, { connectable:false });
NRF.setAdvertising({}, { connectable:false });
</syntaxhighlight>
</syntaxhighlight>
Строка 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().
{{Примечание1|Вы больше не сможете программировать [[Puck.js]], пока не выполните сброс или не вызовите Bluetooth.setConsole().}}


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


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


<syntaxhighlight lang="javascript" enclose="div">
<syntaxhighlight lang="javascript">
NRF.on('connect',function(addr) {
NRF.on('connect',function(addr) {
   if (addr!="69:2d:94:d0:9d:97 public")
   if (addr!="69:2d:94:d0:9d:97 public")
Строка 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">
devices = [];
devices = [];
NRF.on('connect',function(addr) {
NRF.on('connect',function(addr) {
Строка 63: Строка 63:
</syntaxhighlight>
</syntaxhighlight>


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


Примечание: MAC-адреса можно менять, так что этот метод надёжен не на 100%. Впрочем, шансы на то, что кто-то угадает правильный MAC-адрес – не находясь при этом в области подключения в момент, когда соединение активно, чтобы иметь возможность его прослушать – крайне малы.
{{Примечание1|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">
NRF.setServices(undefined, {
NRF.setServices(undefined, {
   uart : false
   uart : false
Строка 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">
var locked = true;
var locked = true;
NRF.setServices(undefined,{uart:!locked}­);
NRF.setServices(undefined,{uart:!locked}­);
Строка 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">
var locked = false;
var locked = false;
setWatch(function() {
setWatch(function() {
Строка 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">
NRF.setSecurity({passkey:"123456", mitm:1, display:1});
NRF.setSecurity({passkey:"123456", mitm:1, display:1});
</syntaxhighlight>
</syntaxhighlight>
Строка 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().


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


=См.также=
=См.также=
{{ads}}


=Внешние ссылки=
=Внешние ссылки=
Строка 145: Строка 143:
<references />
<references />


{{Навигационная таблица/Espruino}}
{{Навигационная таблица/Портал/Espruino}}
{{Навигационная таблица/Телепорт}}

Текущая версия от 17:03, 22 мая 2023

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


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

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

См.также

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