11.13. Asocierea și legarea (pairing și bonding)¶
Tot ceea ce am acoperit până aici transmite octeți prin radio în clar. Oricine are un laptop cu BLE în aceeași încăpere poate asculta canalele de advertising, urmări secvența de salt a unei conexiuni deschise și citi fiecare operație de citire, scriere și notificare care trece. Pentru majoritatea datelor publice de la senzori (nivelul bateriei, temperatura ambiantă) acest lucru este acceptabil. Pentru orice doresc cele două capete să păstreze privat – un registru de control care armează un releu, o parolă, o măsurătoare care nu ar trebui difuzată pe scară largă – legătura trebuie criptată, iar ideal camera trebuie să știe cu cine vorbește.
BLE oferă ambele prin pairing și bonding.
11.13.1. Pairing, bonding, criptare¶
Trei concepte strâns legate:
Criptarea este obiectivul final. Odată ce legătura este criptată, fiecare pachet de pe canalele de date poate fi descifrat doar de cele două capete; un ascultător neautorizat vede doar zgomot.
Pairing este procedura pe care o execută cele două capete pentru a conveni asupra cheilor pe care le folosește criptarea. Este un schimb unic care produce material de cheie partajat pe care nivelul de legătură îl introduce în motorul său de criptare.
Bonding este alegerea de a păstra cheile în memoria nevolatilă după ce pairing se încheie, astfel încât următoarea conexiune între aceleași două dispozitive sare peste pairing și trece direct la criptare.
Pe scurt: pairing înseamnă „prezentați-vă”; bonding înseamnă „rețineți această prezentare”; criptarea înseamnă „vorbiți în privat de acum înainte”.
Fluxul de pairing peste o conexiune BLE deschisă. Odată ce schimbul de chei se finalizează, nivelul de legătură criptează fiecare pachet ulterior. Bonding este pasul suplimentar de scriere a cheilor în memoria flash.¶
11.13.2. LE Secure Connections¶
Schimbul modern de chei folosit de BLE este LE Secure Connections, construit pe Elliptic Curve Diffie-Hellman. Ambele părți generează o pereche temporară de chei, schimbă jumătățile publice și combină rezultatul cu propriile chei private pentru a ajunge la același secret partajat – un secret pe care un ascultător neautorizat nu îl poate calcula nici măcar cu o înregistrare completă a schimbului.
Metoda mai veche LE Legacy este mai puțin sigură (un ascultător neautorizat cu schimbul complet poate de obicei recupera cheia) și există doar pentru compatibilitatea retroactivă cu perifericele vechi. Implicit, aioble folosește metoda modernă (le_secure=True); păstrați-o.
11.13.3. Inițierea pairing-ului¶
Un central realizează pairing apelând aioble.DeviceConnection.pair() pe o conexiune deja deschisă:
async with await device.connect() as connection:
await connection.pair(bond=True, le_secure=True, mitm=False)
# ... GATT work, now over an encrypted link ...
După ce pair revine, atributele encrypted, authenticated, bonded și key_size ale conexiunii reflectă ceea ce a fost negociat.
Cele patru argumente cu cuvânt-cheie cele mai utile:
bond=True– salvează cheile rezultate în memoria flash astfel încât următoarea conexiune între aceleași două dispozitive să sară peste handshake-ul de pairing. ImplicitTrue.le_secure=True– folosește LE Secure Connections. ImplicitTrue. Lăsați-l activat.mitm=False– dacă să se solicite protecție man-in-the-middle. Aceasta necesită un canal în afara benzii (un cod numeric afișat pe o parte și confirmat pe cealaltă, o cheie de acces tastată, …) astfel încât utilizatorul să poată verifica faptul că cele două dispozitive din handshake-ul de pairing sunt într-adevăr cele la care se gândește. Implicit esteFalse(fără protecție MITM – un ascultător pasiv neautorizat nu poate citi legătura, dar un atacator care redirecționează activ conexiunile s-ar putea asocia el însuși). Setați laTruepentru orice este sensibil, dar fiți conștienți că aceasta necesită ca perifericul să suporte efectiv o capacitate IO.io=3– capacitatea IO pe care o declară dispozitivul. Specificația Bluetooth definește cinci:0doar afișaj,1afișaj + da/nu,2doar tastatură,3fără intrare fără ieșire,4tastatură + afișaj. O cameră fără interfață de utilizator raportează de obicei3; dacă camera în sine are un afișaj, aplicația ar putea afișa confirmarea numerică și folosi1. Combinația capacităților IO ale celor două părți decide dacă o protecție MITM reală este realizabilă.
Perifericele nu apelează ele însele pair – ele răspund la orice inițiază centralul. Dacă pentru o anumită caracteristică este necesară criptarea este o proprietate a modului în care aceasta este declarată în baza de date GATT; biții de acces care impun criptarea fac parte din API-ul bluetooth de nivel scăzut și nu sunt expuși în prezent prin constructorul de caracteristică din aioble.
11.13.4. Bonding – și unde se află cheile¶
Când bond=True, aioble scrie cheile într-un fișier JSON în sistemul de fișiere local. Numele de fișier implicit este ble_secrets.json, scris relativ la directorul de lucru curent. Pe o cameră tocmai pornită, _boot.py a ales deja acel director: /sdcard când este montat un card, /flash în caz contrar – astfel încât fișierul ajunge la /sdcard/ble_secrets.json sau /flash/ble_secrets.json. Fișierul conține intrările necesare pentru re-criptarea legăturii data viitoare când peer-ul legat se reconectează, inclusiv adresa de identitate a peer-ului.
O asimetrie de reținut: salvarea are loc automat pe măsură ce cheile se modifică, dar încărcarea fișierului la următoarea pornire nu. Apelați aioble.security.load_secrets() o singură dată la pornire (înainte de orice pairing sau advertising) astfel încât peer-ii legați anterior să fie recunoscuți:
import aioble
aioble.security.load_secrets() # default path: ble_secrets.json
După aceea, data viitoare când apare un peer legat, aioble reutilizează cheile stocate și legătura devine criptată fără niciun handshake suplimentar.
Două consecințe practice ale stocării cheilor în memoria flash:
Uitarea unui dispozitiv. Ștergeți
ble_secrets.json(sau eliminați intrarea relevantă) pentru a uita toți peer-ii legați, apoi refaceți pairing de la zero.Accesul fizic divulgă cheile. Oricine are acces la sistemul de fișiere al camerei poate citi fișierul JSON. Aceasta este aceeași constrângere care a apărut și pe partea de rețea cu cheile TLS (Operațiuni: chei, expirare și depanare): folosiți chei per-dispozitiv, tratați orice cheie stocată ca recuperabilă și bazați-vă pe capacitatea de a revoca (aici, eliminarea legăturii de pe partea centralului) mai degrabă decât pe păstrarea secretă a cheii.
11.13.5. Ce garantează criptarea – și ce nu¶
O legătură pairing-apoi-criptare oferă, în ordinea puterii:
Confidențialitate. Întotdeauna. Un ascultător neautorizat nu poate citi octeții.
Integritate. Întotdeauna. Pachetele modificate nu trec verificarea de criptare autentificată a nivelului de legătură și sunt eliminate.
Autentificare. Doar cu
mitm=Trueși o capacitate IO adecvată. Fără ea, un man-in-the-middle care a interceptat schimbul de pairing original s-ar fi putut insera; fără protecție MITM nu există nicio modalitate prin care cele două părți să afle.
Pentru majoritatea cazurilor de utilizare a camerei – un telefon care se asociază cu camera o dată, apoi se conectează din nou mai târziu – mitm=False este de obicei suficient, deoarece pairing-ul original are loc într-un mediu controlat (utilizatorul ține ambele dispozitive în aceeași încăpere). Pentru aplicații în care un dispozitiv asociat ar putea întâlni mai întâi camera de la o distanță mare sau printr-un intermediar de încredere îndoielnică, MITM este setarea potrivită.
11.13.6. Când pairing-ul este răspunsul greșit¶
Pairing-ul are un cost real: câteva secunde de schimb la prima conexiune, utilizare persistentă a memoriei flash pentru fiecare dispozitiv legat și scenariul de recuperare „uită legătura” dacă ceva nu merge bine. Pentru date cu adevărat publice – citiri de la senzori ambientali publicate ca un beacon, un panou care își afișează numele, orice nu schimbă lumea prin faptul că este citit sau scris – răspunsul corect este să nu se cripteze deloc, lăsând orice scanner din apropiere să citească valorile.
Pentru orice altceva, connection.pair(bond=True) pe central este adăugarea de o singură linie care transformă legătura dintr-un canal public într-unul privat.