14.4.5. Nyilvános szerver ellenőrzése (a kamera mint kliens)¶
Minden, amit az előző oldalon arról írtunk, hogy a kliens „már rendelkezik a gyökérrel”, igaz a böngészőkre, telefonokra és PC-kre – de a kamerára nem igaz. A MicroPython ssl modulja semmilyen beépített megbízhatósági tárolóval nem érkezik: egy frissen flashelt kamera egyetlen CA-ban sem bízik meg, az alapértelmezett mód (ssl.CERT_NONE) pedig semmit sem ellenőriz, így teljesen kiszolgáltatott a köztes ember (man-in-the-middle) támadásnak. Tehát amikor a kamera a kliens, amely kifelé csatlakozik egy nyilvános TLS szerverhez (egy HTTPS API-hoz, egy MQTT brókerhez, …), és valóban szeretnéd, hogy ellenőrizze ezt a szervert, akkor neked magadnak kell biztosítanod a megbízhatósági horgonyt.
A működés ugyanaz, mint a Önaláírt tanúsítványok oldalon bemutatott önaláírt kliens példában; az egyetlen különbség az, hogy a betöltött fájl egy valódi CA tanúsítvány a partner saját tanúsítványa helyett:
Szerezd be azt a CA tanúsítványt, amely a szerver láncát horgonyozza. A „horgonyzás” azt a tanúsítványt jelenti, amely a szerver láncának tetején (vagy ahhoz közel) helyezkedik el, és amelyet a megbízhatóság kiindulópontjának választasz. Egy TLS szerver elküldi a levél (leaf) tanúsítványát, és általában a köztes (intermediate) tanúsítványát is; a gyökerét viszont soha nem küldi el. Ezt a megbízhatósági horgonyt magadnak kell beszerezned, a szervertől függetlenül – ha egyszerűen csak megbíznál abban, amit a szerver átad, az az ellenőrzés egész lényegét aláásná.
Először derítsd ki, hogy melyik CA állította ki ténylegesen a szerver tanúsítványát. Például az
openmv.ioesetében:openssl s_client -connect openmv.io:443 -showcerts < /dev/nullA
Certificate chainblokk minden tanúsítványt felsorol a tárgyával (s:) és a kibocsátójával (i:); az újabb OpenSSL emellett kiíra:(kulcstípus) ésv:(érvényesség) sorokat is, amelyeket itt figyelmen kívül hagyhatsz:Certificate chain 0 s:CN=openmv.io i:C=US, O=Let's Encrypt, CN=E8 1 s:C=US, O=Let's Encrypt, CN=E8 i:C=US, O=Internet Security Research Group, CN=ISRG Root X1
A 0. bejegyzés a levél (
openmv.io), amelyet azE8köztes tanúsítvány bocsátott ki. Az 1. bejegyzés maga ez a köztes tanúsítvány, amelyet azISRG Root X1gyökér bocsátott ki. A legfelső bejegyzés kibocsátója (i:) nevezi meg a gyökeret – itt azISRG Root X1-et. (A köztes tanúsítvány ittE8, nem pedig azR10/R11, amelyet máshol láthattál, mert azopenmv.ioECDSA tanúsítványt használ; a Let’s Encrypt az ECDSA leveleket azE-sorozatú köztes tanúsítványaival írja alá, az RSA leveleket pedig azR-sorozatúakkal. Mindkettő azISRG Root X1-hez vezet vissza.)Az OpenSSL
depth=sorokat is kiír, és a gyökeret esetlegVerification: OKjelzéssel jelentheti. Ez azonban csak azért történik, mert a te PC-d már megbízik azISRG Root X1-ben – a szerver azt nem küldte el (egy szerver soha nem küldi el a gyökerét), és a kamera, amelynek nincs megbízhatósági tárolója, szintén nem fog rendelkezni vele. Pontosan ezért kell neked biztosítanod azt.Töltsd le azt a gyökeret a CA saját közzétett gyökereiből. A Let’s Encrypt mindegyiket katalogizálja a Let’s Encrypt tanúsítványok oldalán; az ISRG Root X1 közvetlen fájlja az isrgrootx1.pem (előre kódolva is kínálják isrgrootx1.der formában). Más CA-k hasonló „root certificates” / „repository” oldalon teszik közzé a sajátjaikat; a kanonikus nyilvános gyűjtemény a Mozilla CA program (CCADB). Győződj meg róla, hogy a megfelelő fájlt töltötted le, úgy, hogy összehasonlítod az ujjlenyomatát a CA által közzétett értékkel (add hozzá a
-inform DERkapcsolót, ha a.derváltozatot töltötted le):openssl x509 -in isrgrootx1.pem -noout -subject -fingerprint -sha256Ha inkább nem szeretnél egy gyökeret nyomon követni, ehelyett kimásolhatod a köztes tanúsítványt közvetlenül a
-showcertskimenetéből (a második-----BEGIN CERTIFICATE-----blokk), megbízhatsz benne, de el kell fogadnod, hogy frissítened kell, valahányszor a CA lecseréli a köztes tanúsítványt – ami sokkal gyakrabban történik, mint a gyökérnél (lásd az alábbi kompromisszumot).Konvertáld DER formátumba, pontosan úgy, mint korábban:
openssl x509 -in isrgrootx1.pem -outform DER -out ca.derMásold a
ca.derfájlt a kamerára (fájlrendszerbe vagy ROMFS-be), és töltsd be megbízhatósági horgonyként:import socket import ssl import ntptime ntptime.settime() # validity check needs the clock addr = socket.getaddrinfo("api.example.com", 443)[0][-1] sock = socket.socket() sock.connect(addr) ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ctx.verify_mode = ssl.CERT_REQUIRED ctx.load_verify_locations(cafile="ca.der") ssock = ctx.wrap_socket(sock, server_hostname="api.example.com")
A
server_hostnameitt kötelező: ez vezérli az SNI-t, és ez az a név, amelyet a szerver tanúsítványánaksubjectAltNamemezőjével vetnek össze.
Javaslat
Gyakori eset gyorsmegoldása. A Let’s Encrypt a legszélesebb körben használt nyilvános CA, és jelenleg mind az RSA, mind az ECDSA tanúsítványai az ISRG Root X1-hez vezetnek vissza (ahogy a fenti openmv.io példa is mutatja). Ha a kamerád által megszólított szerverek a Let’s Encryptet használják, az ellenőrzést teljesen kihagyhatod: csak tedd fel az isrgrootx1.der fájlt a kamerára, és töltsd be a load_verify_locations hívással.
Ez nem teszi lehetővé, hogy a TLS minden oldallal működjön. Egy olyan szerver, amelynek tanúsítványa más CA-tól származik (DigiCert, Google Trust Services, Amazon, Sectigo, …), továbbra is megbukik az ellenőrzésen, és mivel a kamera ssl.SSLContext példányonként egyetlen DER tanúsítványban bízik meg, nem tudod úgy összecsomagolni az összes gyökeret, ahogy egy böngésző teszi. Kétség esetén azonosítsd a szerver tényleges CA-ját a fent bemutatott módon, és abban a gyökérben bízz meg.
Hogy melyik tanúsítványban bízol meg, az kompromisszum kérdése:
A gyökér (ajánlott). Hosszú élettartamú – gyakran évtizedekig él – így a
ca.derritkán változik. Megköveteli, hogy a szerver elküldje a köztes tanúsítványát, hogy az mbedTLS felépíthesse az utat levél → köztes → a megbízható gyökered; gyakorlatilag minden helyesen konfigurált nyilvános szerver megteszi ezt.A köztes tanúsítvány. Szintén működik, és akkor is működik, ha egy szerver elhagyja a köztes tanúsítványt, de a köztes tanúsítványokat sokkal gyakrabban cserélik, mint a gyökereket, így gyakrabban kell majd frissítened a
ca.derfájlt.Maga a levél (tanúsítvány-rögzítés, pinning). A legszorosabb, de a levél minden megújításkor megváltozik – a Let’s Encrypt esetén nagyjából 90 naponta – így ennek csak akkor van értelme, ha a szervert is te felügyeled, és az új rögzítést egyszerre minden kamerára ki tudod tolni. Pontosan ezt teszi az önaláírt kliens példa.
Megjegyzés
A ssl.SSLContext.load_verify_locations() egyetlen DER-kódolt CA tanúsítványt fogad, így a kamera egyszerre pontosan egy horgonyban bízik meg. Ahhoz, hogy különböző CA-k alá tartozó szervereket érj el, használj horgononként külön ssl.SSLContext példányt. És mivel ez a tanúsítvány maga is végül lejár, vagy a CA lecseréli, kezeld úgy, mint bármely más tanúsítványt az eszközön.