11.13. Сполучення і зв’язування

Все, що розглядалось до цього моменту, передає байти через радіоканал у відкритому вигляді. Будь-хто з BLE-сумісним ноутбуком у тій самій кімнаті може прослуховувати канали реклами, відстежувати послідовність перемикання каналів відкритого з’єднання та зчитувати кожне читання, запис і сповіщення, що проходять через нього. Для більшості публічних даних датчиків (рівень заряду батареї, температура навколишнього середовища) це прийнятно. Для всього, що обидві кінцеві точки хочуть зберегти в таємниці – регістру керування, що активує реле, пароля, вимірювання, яке не слід широко поширювати – канал зв’язку потребує шифрування, і в ідеалі камера повинна знати, з ким вона розмовляє.

BLE забезпечує обидва аспекти через сполучення і зв’язування.

11.13.1. Сполучення, зв’язування, шифрування

Три тісно пов’язані поняття:

  • Шифрування є кінцевою метою. Після шифрування каналу зв’язку кожен пакет у каналах даних може розшифрувати лише дві кінцеві точки; підслуховувач бачить лише шум.

  • Сполучення – це процедура, яку виконують дві кінцеві точки для узгодження ключів, що використовуються при шифруванні. Це одноразовий обмін, що генерує спільний ключовий матеріал, який рівень каналу зв’язку передає до свого модуля шифрування.

  • Зв’язування – це вибір зберегти ключі у енергонезалежній пам’яті після завершення сполучення, щоб наступне з’єднання між тими самими двома пристроями пропустило сполучення і перейшло безпосередньо до шифрування.

Простими словами: сполучення – це «познайомтеся»; зв’язування – це «запам’ятайте це знайомство»; шифрування – це «говоріть приватно з цього моменту».

Two columns labelled "Central" and "Peripheral". A dashed line near the top labelled "BLE connection open (unencrypted)". Below it, three arrows: "pairing request" from central to peripheral, "key exchange" both directions, "pairing complete" forward. A second dashed line below labelled "link encrypted". Two thick bidirectional arrows carry "encrypted GATT traffic". An optional "store keys to flash" box on the side, labelled "bonding".

Процес сполучення поверх відкритого BLE-з’єднання. Після завершення обміну ключами рівень каналу зв’язку шифрує кожен наступний пакет. Зв’язування – це додатковий крок запису ключів у флеш-пам’ять.

11.13.2. LE Secure Connections

Сучасний метод обміну ключами, що використовується BLE, – LE Secure Connections, побудований на основі еліптичних кривих Діффі-Геллмана. Обидві сторони генерують тимчасову пару ключів, обмінюються публічними половинами та комбінують результат зі своїми власними приватними ключами, отримуючи однаковий спільний секрет – секрет, який підслуховувач не може обчислити навіть маючи повний запис обміну.

Старіший метод LE Legacy є менш безпечним (підслуховувач з повним записом обміну зазвичай може відновити ключ) і існує лише для зворотної сумісності зі старими периферійними пристроями. За замовчуванням aioble використовує сучасний метод (le_secure=True); зберігайте його.

11.13.3. Ініціювання сполучення

Центральний пристрій виконує сполучення, викликаючи aioble.DeviceConnection.pair() на вже відкритому з’єднанні:

async with await device.connect() as connection:
    await connection.pair(bond=True, le_secure=True, mitm=False)
    # ... GATT work, now over an encrypted link ...

Після повернення з pair атрибути encrypted, authenticated, bonded та key_size з’єднання відображають результат переговорів.

Чотири найбільш корисних іменованих аргументи:

  • bond=True – зберегти отримані ключі у флеш-пам’ять, щоб наступне з’єднання між тими самими двома пристроями пропустило процедуру сполучення. За замовчуванням True.

  • le_secure=True – використовувати LE Secure Connections. За замовчуванням True. Залишайте увімкненим.

  • mitm=False – чи вимагати захисту від атак людина посередині. Для цього потрібен позасмуговий канал (числовий код, що відображається з одного боку і підтверджується з іншого, введений ключ доступу, …), щоб користувач міг перевірити, що два пристрої в процедурі сполучення – саме ті, що він очікує. За замовчуванням False (без захисту від MITM – пасивний підслуховувач не може зчитати канал зв’язку, але зловмисник, що активно перенаправляє з’єднання, може здійснити сполучення від свого імені). Встановлюйте True для будь-чого чутливого, але майте на увазі, що це вимагає від периферійного пристрою підтримки певної можливості вводу-виводу.

  • io=3 – можливість вводу-виводу, яку оголошує пристрій. Специфікація Bluetooth визначає п’ять: 0 лише дисплей, 1 дисплей + так/ні, 2 лише клавіатура, 3 немає вводу немає виводу, 4 клавіатура + дисплей. Камера без UI зазвичай оголошує 3; якщо сама камера має дисплей, застосунок може відображати числове підтвердження і використовувати 1. Комбінація можливостей вводу-виводу обох сторін визначає, чи досяжний реальний захист від MITM.

Периферійні пристрої не викликають pair самостійно – вони відповідають на те, що ініціює центральний пристрій. Чи вимагається шифрування для певної характеристики – це властивість того, як вона оголошена в базі даних GATT; біти доступу, що вимагають шифрування, є частиною низькорівневого API bluetooth і наразі не виставлені через конструктор характеристик aioble.

11.13.4. Зв’язування – і де зберігаються ключі

При bond=True aioble записує ключі у файл JSON у локальній файловій системі. Стандартне ім’я файлу – ble_secrets.json, що записується відносно поточного робочого каталогу. На свіжо завантаженій камері _boot.py вже вибрав цей каталог: /sdcard якщо карта підключена, /flash в іншому випадку – тому файл розміщується у /sdcard/ble_secrets.json або /flash/ble_secrets.json. Файл містить записи, необхідні для повторного шифрування каналу зв’язку наступного разу, коли зв’язаний вузол повторно підключиться, включаючи ідентифікаційну адресу вузла.

Одна асиметрія, яку слід пам’ятати: збереження відбувається автоматично при зміні ключів, але завантаження файлу при наступному завантаженні – ні. Викликайте aioble.security.load_secrets() один раз при запуску (до будь-якого сполучення або реклами), щоб раніше зв’язані вузли розпізнавались:

import aioble
aioble.security.load_secrets()        # default path: ble_secrets.json

Після цього наступного разу, коли з’явиться зв’язаний вузол, aioble повторно використає збережені ключі і канал зв’язку зашифрується без додаткової процедури погодження.

Два практичних наслідки зберігання ключів у флеш-пам’яті:

  • Видалення пристрою. Видаліть ble_secrets.json (або відповідний запис), щоб забути всіх зв’язаних вузлів, а потім виконайте сполучення з нуля.

  • Фізичний доступ розкриває ключі. Будь-хто з доступом до файлової системи камери може прочитати JSON. Це та сама ситуація, що виникала на стороні мережі з ключами TLS (Операції: ключі, термін дії та усунення несправностей): використовуйте ключі для кожного пристрою окремо, вважайте будь-який збережений ключ відновлюваним і покладайтесь на можливість відкликання (тут – видалення зв’язку з боку центрального пристрою), а не на те, що ключ залишиться в таємниці.

11.13.5. Що гарантує шифрування – і що не гарантує

З’єднання з сполученням і наступним шифруванням забезпечує, в порядку від сильнішого до слабшого:

  • Конфіденційність. Завжди. Підслуховувач не може прочитати байти.

  • Цілісність. Завжди. Змінені пакети не проходять перевірку аутентифікованого шифрування на рівні каналу зв’язку і відкидаються.

  • Аутентифікація. Лише при mitm=True і відповідній можливості вводу-виводу. Без цього зловмисник «людина посередині», що перехопив оригінальний обмін при сполученні, міг би вставити себе в ланцюжок; без захисту від MITM немає способу для обох сторін дізнатись про це.

Для більшості випадків використання камери – телефон, що одного разу сполучується з камерою, а потім повторно підключається – mitm=False зазвичай достатньо, оскільки початкове сполучення відбувається в контрольованому середовищі (користувач тримає обидва пристрої в одній кімнаті). Для застосунків, де сполучений пристрій може вперше зустріти камеру на великій відстані або через ненадійний посередник, MITM є правильним налаштуванням.

11.13.6. Коли сполучення – неправильна відповідь

Сполучення має реальну вартість: кілька секунд обміну при першому підключенні, постійне використання флеш-пам’яті для кожного зв’язаного пристрою, і процедура відновлення «забудьте зв’язок», якщо щось пішло не так. Для справді публічних даних – показань датчиків навколишнього середовища, опублікованих як маяк, вивіски, що відображає своє ім’я, всього, що не змінює стан системи при читанні або записі – правильна відповідь – не шифрувати взагалі, і дозволити будь-якому сканеру поблизу читати значення.

Для всього іншого connection.pair(bond=True) на центральному пристрої – це однорядкове доповнення, що перетворює канал зв’язку з публічного на приватний.