Styra ESP8266 utan port forwarding: en utgående MQTT-väg
En broker som nås från internet låter en enhet hemma styras över en anslutning som den själv öppnade. Vad det ändrar för TLS-minne, ämnen och upprepning.
Enheten sitter bakom en hemmarouter utan port forwarding och utan offentlig adress, och måste ändå ta emot konfiguration inom sekunder. Tricket är inte ett hål i brandväggen. Det är en anslutning som enheten öppnar utåt mot en broker den kan nå, och som sedan skickar tillbaka meddelandena samma etablerade väg. Varje egenskap folk gillar med den här designen, och varje fälla i den, kommer från den inversionen.
Vad som faktiskt tar sig igenom NAT
När enheten öppnar en TCP-anslutning till brokern skapar hemmaroutern en mappning och håller den vid liv så länge flödet varar. Svar på det flödet kommer tillbaka till enheten eftersom mappningen redan finns. Brokern initierar aldrig något mot huset, så det finns inget oombett inkommande paket som routern måste avvisa. Det är hela nätverksargumentet, och därför fungerar angreppssättet på nätverk du inte kontrollerar.
Enheten måste hålla anslutningen vid liv eller återupprätta den, vilket blir tillförlitlighetsfrågan när arkitekturen är fastställd.
Brokern dirigerar ämnen, den proxar inte HTTP
MQTT definierar utbyten för publicering och prenumeration: enheten prenumererar på ett ämnesfilter den får läsa, och en behörig styrenhet publicerar till ett matchande ämne. Brokern matchar publiceringar mot prenumerationer och levererar kopior. Den vet inte vad en webbläsarförfrågan är, och den vidarebefordrar inte en HTTP GET till enhetens webbserver. Om den befintliga firmwaren bara talar HTTP behöver brokerdesignen en applikationsändring eller en medveten översättningskomponent.
Ämnesnamn är inte heller behörighet. De flesta brokrar stöder åtkomstkontrollistor per klient, och enheter bör begränsas till sina egna publicerings- och prenumerationsträd i stället för att dela ett globalt namnutrymme.
Enhetens resurser avgör TLS-formen
En ESP8266 har begränsat RAM, och ett TLS-handskakning är det dyraste den gör. Arduino-kärnan levererar BearSSL just på grund av den begränsningen, och valet mellan att verifiera en CA och att fästa ett fingeravtryck ändrar både minnesavtrycket och vad en angripare med ett giltigt certifikat för ett annat namn kan göra. Att verifiera brokerns CA är det starkare alternativet när heapen tillåter det. Nyttolastens storlek spelar också roll: MQTT-klienten håller en buffert, och meddelanden som är större än den trunkeras tyst om bufferten inte höjs medvetet.
Keepalive och socket-timeouts är en del av samma budget, eftersom en klient som aldrig märker en död anslutning slutar ta emot kommandon utan att rapportera ett fel.
Meddelandesemantiken som biter
Ett kvarhållet meddelande lagras av brokern och levereras till senare matchande prenumeranter, vilket är utmärkt för aktuellt tillstånd och farligt för engångskommandon: en enhet som återansluter kan ta emot gårdagens kommando som om det vore nytt. QoS 1 garanterar leverans minst en gång, så dubbletter är normala och applikationen måste vara säker mot upprepning, helst med en identifierare eller tidsstämpel som den kan avvisa. Det sista testamentet ger dig en statussignal när enheten faller ifrån, men bara om anslutningen faktiskt misslyckas i stället för att hänga.
Beteendet för en ren session avgör om brokern behåller dina prenumerationer medan du är borta, och att göra fel där är anledningen till att vissa enheter missar det första meddelandet efter varje återanslutning.
TLS skyddar sträckan till brokern. Det är inte ende-till-ende-kryptering av nyttolasten mot brokeroperatören, som kan läsa allt du publicerar genom den.
Begränsa livscykeln och testa den med ofarliga data
Planera återanslutning med backoff i stället för en tät återförsöksslinga, prenumerera uttryckligen igen om sessionen inte är beständig, och logga anslutningsresultatet så att en tyst offline-enhet lämnar bevis. Testa återanslutningsvägen med exempelnyttolaster som inte gör något, eftersom det första produktionstestet av en kommandokanal inte bör vara ett riktigt kommando. Bekräfta sedan vad ett inaktuellt kvarhållet meddelande gör vid återanslutning, och bestäm om det beteendet är acceptabelt för varje ämne.
Gjort på detta sätt tar designen bort ett inkommande nätverkskrav och lämnar enhetsprogramvaran, brokerpolicyn och meddelandesemantiken som synligt arbete i stället för dolda antaganden.