{"id":27844,"date":"2020-10-27T11:26:23","date_gmt":"2020-10-27T10:26:23","guid":{"rendered":"https:\/\/pi3g.com\/?p=27844"},"modified":"2020-10-27T11:26:23","modified_gmt":"2020-10-27T10:26:23","slug":"the-technology-security-foundations-of-picockpit","status":"publish","type":"post","link":"https:\/\/pi3g.com\/de\/the-technology-security-foundations-of-picockpit\/","title":{"rendered":"Die Technologie- und Sicherheitsgrundlagen von PiCockpit"},"content":{"rendered":"<p>Ich wurde gebeten, ein wenig \u00fcber die Sicherheits- und Technologiegrundlagen von <a href=\"https:\/\/picockpit.com\/\">PiCockpit<\/a>.<\/p>\n<h1>Die beteiligten Teile<\/h1>\n<p>PiCockpit besteht aus mehreren Teilen:<\/p>\n<ul>\n<li>picockpit-client<\/li>\n<li>picockpit-Frontend<\/li>\n<li>picockpit-backend<\/li>\n<li>picockpit-api (\"papi\")<\/li>\n<li>die Datenbank<\/li>\n<li>den MQTT-Server<\/li>\n<li>das picockpit Paket-Repository<\/li>\n<\/ul>\n<h2>Der MQTT-Server<\/h2>\n<p>Der Datenaustausch zwischen picockpit-frontend und picockpit-client erfolgt \u00fcber den MQTT-Server (genannt \"Broker\") via Websockets. Wir verwenden <a href=\"https:\/\/vernemq.com\/\">VerneMQ<\/a> zu diesem Zweck. <\/p>\n<p>MQTT ist ein Kommunikationsprotokoll, \u00e4hnlich wie HTTP. Es basiert auf der Ver\u00f6ffentlichungs-\/Abonnement-Metapher, im Gegensatz zu HTTP (das auf Anfrage\/Antwort basiert).<\/p>\n<p>In MQTT k\u00f6nnen sich Clients mit dem Broker verbinden und Topics abonnieren - in diesem Fall erhalten sie Nachrichten, die in diesen Topics ver\u00f6ffentlicht werden. Sie k\u00f6nnen auch Nachrichten in Topics ver\u00f6ffentlichen. <\/p>\n<p>In diesem Fall bewahrt der Broker die Nachricht auf und sendet sie an jeden Client, der das entsprechende Thema abonniert hat, in dem die Nachricht ver\u00f6ffentlicht wurde.<\/p>\n<p>In regelm\u00e4\u00dfigen Abst\u00e4nden werden Keepalives vom Broker zum Client und zur\u00fcck gesendet, um die Verbindung aufrechtzuerhalten und sicherzustellen, dass der Client noch online ist. <\/p>\n<p>Dar\u00fcber hinaus kann eine Nachricht \"Letzter Wille und Testament\" eingerichtet werden, die ver\u00f6ffentlicht wird, wenn der Broker die Verbindung zum Kunden verliert.<\/p>\n<p>Jeder Raspberry Pi erh\u00e4lt seinen eigenen Nachrichten-Themenpfad, die Seriennummer des Raspberry Pi wird zu diesem Zweck verwendet.<\/p>\n<p>Nach meinen Recherchen ist VerneMQ die perfekte Wahl, um als MQTT-Broker f\u00fcr PiCockpit zu dienen: <\/p>\n<ul>\n<li>es ist ausschlie\u00dflich auf MQTT ausgerichtet (im Gegensatz zu RabbitMQ)<\/li>\n<li>der Schwerpunkt liegt auf hoher Leistung und hoher Verf\u00fcgbarkeit<\/li>\n<\/ul>\n<p>VerneMQ ist in Erlang geschrieben. Erlang ist eine gute Sprache\/Umgebung f\u00fcr Telekommunikationsanwendungen - sie ist f\u00fcr hochgradige Gleichzeitigkeit und Skalierbarkeit ausgelegt, auch \u00fcber mehrere Knoten hinweg. Au\u00dferdem ist sie sehr leichtgewichtig f\u00fcr die Verarbeitung einzelner Nachrichten, so dass sie auf Millionen von Nachrichten skaliert werden kann. Die Website <a href=\"https:\/\/vernemq.com\/blog\/index.html\">VerneMQ-Blog<\/a> ist eine faszinierende Lekt\u00fcre. <\/p>\n<h3>Sicherheitsmerkmale<\/h3>\n<p>VerneMQ erm\u00f6glicht es uns, verschiedene Mountpoints zu verwenden, um den Datenverkehr f\u00fcr einzelne Benutzer vollst\u00e4ndig zu trennen. <\/p>\n<p>Der picockpit-client und das picockpit-frontend eines Benutzers k\u00f6nnen nur Nachrichten im Mountpoint dieses Benutzers sehen.<\/p>\n<p>Der Einh\u00e4ngepunkt wird auf der Grundlage der Authentifizierungsdaten zugewiesen, die einen Rasberry Pi (picockpit-client) oder eine JavaScript-Verbindung (picockpit-frontend) als dem jeweiligen Benutzer zugeh\u00f6rig ausweisen. <\/p>\n<h3>Warum Websockets? <\/h3>\n<p>Websockets erm\u00f6glichen es dem Datenverkehr, Firewalls zu \u00fcberwinden, und sind die einzige M\u00f6glichkeit, wie der JavaScript-Client kommunizieren kann.<\/p>\n<p><\/p>\n<h2>Der picockpit-Client<\/h2>\n<p>Der picockpit-Client ist in Python geschrieben und verwendet zahlreiche Bibliotheken. Er wird als Debian-Paket (.deb) verpackt und mit unserem Schl\u00fcssel signiert in unserem \u00f6ffentlichen Repository bereitgestellt. <\/p>\n<p>F\u00fcr die MQTT-Kommunikation verwenden wir Paho. Paho ist eine Open-Source-Bibliothek. Wir verwenden Paho auch im picockpit-Frontend. <\/p>\n<p>Der picockpit-client wird in einem Setup-Prozess mit PiCockpit verbunden (sudo picockpit-client connect).<\/p>\n<p>Bei diesem Verfahren kommuniziert der Client mit der API unter Verwendung eines API-Schl\u00fcssels, um MQTT-Anmeldeinformationen zu erhalten. <\/p>\n<p>Sowohl der API-Schl\u00fcssel als auch die MQTT-Zugangsdaten werden auf dem Raspberry Pi des Benutzers in verschl\u00fcsselter Form (einschlie\u00dflich Salz!) gespeichert. <\/p>\n<p>Der picockpit-Client ist so konzipiert, dass er st\u00e4ndig online ist, wenn der Pi des Nutzers online und mit dem Internet verbunden ist. Auf diese Weise k\u00f6nnen die Daten des Pi ausgelesen werden und er kann vom Benutzer auf sichere Weise gesteuert werden. <\/p>\n<p>Durch die Deaktivierung des picockpit-client Dienstes kann sich picockpit.com nicht mehr mit dem Pi verbinden und Daten empfangen bzw. Steuerbefehle senden. <\/p>\n<p>Der picockpit-client speichert lokale Konfigurationsdateien im Verzeichnis \/etc\/picockpit-client<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/image-91.png\"><img loading=\"lazy\" decoding=\"async\" width=\"452\" height=\"361\" title=\"Bild\" style=\"display: inline; background-image: none;\" alt=\"Bild\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/image_thumb-90.png\" border=\"0\"><\/a><\/p>\n<p>Eine Beispielstruktur sehen Sie in der oben angegebenen Verzeichnisstruktur.<\/p>\n<p>Die wichtigste Konfigurationsdatei ist picockpit-client.config.json. Diese Datei enth\u00e4lt die notwendigen Anmeldedaten f\u00fcr den picockpit-client, um sich mit PiCockpit.com zu verbinden.<\/p>\n<p>Au\u00dferdem sehen Sie zwei Verzeichnisse apps\/com.picockpit\/picontrol\/modules und apps\/com.picockpit\/pidoctor\/modules<\/p>\n<p>Diese enthalten .json-Dateien, d.h. Definitionsdateien f\u00fcr die Befehle, die Sie aktiv \u00fcber das Frontend in diesen speziellen Anwendungen ausf\u00fchren k\u00f6nnen. <\/p>\n<p>Wenn Sie z.B. die Reboot- oder Shutdown-Buttons in PiCockpit.com nicht anzeigen m\u00f6chten und PiCockpit die Nutzung dieser Funktionen verbieten wollen, m\u00fcssen Sie <\/p>\n<p>apps\/com.picockpit\/picontrol\/modules\/core.json<\/p>\n<p>und starten Sie den picockpit-client Dienst neu<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/image-92.png\"><img loading=\"lazy\" decoding=\"async\" width=\"561\" height=\"421\" title=\"Bild\" style=\"display: inline; background-image: none;\" alt=\"Bild\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/image_thumb-91.png\" border=\"0\"><\/a><\/p>\n<p>Wie Sie sehen k\u00f6nnen, enthalten diese Dateien Definitionen f\u00fcr die Befehle, die im Web-Frontend angezeigt werden. <\/p>\n<p>Wenn Sie die Funktionalit\u00e4t erweitern und zus\u00e4tzliche Befehle oder Module (Befehlsgruppen) hinzuf\u00fcgen m\u00f6chten, k\u00f6nnen Sie dies hier tun, indem Sie die JSON-Dateien bearbeiten oder neue Dateien erstellen.<\/p>\n<p>Befehle werden standardm\u00e4\u00dfig unter dem Benutzer \"pi\" ausgef\u00fchrt. Mit der .JSON-Syntax k\u00f6nnen Sie angeben, unter welchem Benutzer der Befehl ausgef\u00fchrt werden soll. <\/p>\n<p>picockpit-client l\u00e4uft als root, f\u00fcr die Ausf\u00fchrung von Befehlen wird ein neuer Thread gesponnen, dessen Benutzerrechte auf den angegebenen Benutzer ge\u00e4ndert werden. Diese \u00c4nderung f\u00fcr diesen bestimmten Thread ist irreversibel, so dass die Anwendung keine Root-Rechte zur\u00fcckfordern kann.<\/p>\n<p>Die gleichen JSON-Dateien, mit einer etwas anderen Syntax, k\u00f6nnen f\u00fcr PiDoctor erstellt werden.<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/image-93.png\"><img loading=\"lazy\" decoding=\"async\" width=\"564\" height=\"167\" title=\"Bild\" style=\"display: inline; background-image: none;\" alt=\"Bild\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/image_thumb-92.png\" border=\"0\"><\/a><\/p>\n<h3>Sicherheitsmerkmale<\/h3>\n<p>Wie bereits erw\u00e4hnt, k\u00f6nnen die Benutzerrechte f\u00fcr PiControl ge\u00e4ndert werden, indem der Benutzer festgelegt wird. Die Tests von PiDoctor werden derzeit alle als root ausgef\u00fchrt.<\/p>\n<p>Es k\u00f6nnen keine Befehle vom Benutzer im Webinterface definiert werden, diese Befehle m\u00fcssen als JSON-Dateien auf dem jeweiligen Pi existieren, den Sie steuern m\u00f6chten. <\/p>\n<p>Dies soll Sicherheitsprobleme verhindern, selbst wenn jemand Zugang zu Ihrem Webfrontend erh\u00e4lt. <\/p>\n<p>Der Nutzer kann selbst bestimmen, wie viel er von sich preisgeben m\u00f6chte. <\/p>\n<p>Standardm\u00e4\u00dfig wurden dem Webinterface nur die Steuerungsaktionen \"Ausschalten\", \"Neustart\" und \"Picockpit-Client aktualisieren\" hinzugef\u00fcgt.<\/p>\n<p>Die anderen Module (GPIO &amp; PiStats) erlauben es nicht, beliebige Befehle auszuf\u00fchren. PiStats ist derzeit fest auf die Informationen kodiert, die im Webinterface angezeigt werden:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/pistats.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"439\" height=\"552\" title=\"Pistolen\" style=\"display: inline; background-image: none;\" alt=\"Pistolen\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/pistats_thumb.jpg\" border=\"0\"><\/a><\/p>\n<p>\u00dcber GPIO k\u00f6nnen die Pins des Raspberry Pi (einschlie\u00dflich Software-PWM) gesteuert und ausgelesen werden. Vorsicht ist geboten bei der Zuweisung der Pins (nur f\u00fcr den Picockpit-Client, er kennt keine anderen Anwendungen - hier muss man also aufpassen) und bei der Synchronisation von Zust\u00e4nden \u00fcber mehrere Webinterfaces, die auf denselben Pi zugreifen (z.B. wenn der Benutzer gleichzeitig mehrere Browserfenster oder Ger\u00e4te verwendet). <\/p>\n<p>Alle diese Informationen werden mit dem MQTT-Ver\u00f6ffentlichungs-\/Abonnement-Algorithmus \u00fcbertragen. <\/p>\n<p>Schlie\u00dflich l\u00e4uft die Websocket-Kommunikation \u00fcber einen sicheren Port, so dass alle Daten, die bei der Kommunikation mit dem Broker an den Pi gehen oder von ihm empfangen werden, verschl\u00fcsselt werden. <\/p>\n<h2>picockpit-Backend &amp; Datenbank<\/h2>\n<p>Das picockpit Backend ist in der Programmiersprache <a href=\"https:\/\/crystal-lang.org\/\">Kristall<\/a> Programmiersprache, mit <a href=\"https:\/\/kemalcr.com\/\">Kemal<\/a> als Rahmen. <\/p>\n<p>Crystal wurde aufgrund seiner Leistungsf\u00e4higkeit, Entwicklerfreundlichkeit und Typsicherheit ausgew\u00e4hlt. <\/p>\n<p>Crystal spricht mit der Datenbank. Wir verwenden MongoDB als Datenbank. <\/p>\n<h3>Sicherheitsmerkmale<\/h3>\n<ul>\n<li>Passw\u00f6rter werden gehasht und gesalzen<\/li>\n<li>der Benutzer kann mehrere API-Schl\u00fcssel erstellen und diese widerrufen (l\u00f6schen)<\/li>\n<li>der API-Schl\u00fcssel wird au\u00dferdem nur in gehashter und gesalzener Form gespeichert - er kann nicht zur\u00fcckentwickelt werden, selbst wenn jemand Zugang zur Datenbank erh\u00e4lt<\/li>\n<\/ul>\n<p>Sowohl auf der Seite des picockpit-Clients als auch in der Datenbank werden nur gehashte Ableitungen des API-Schl\u00fcssels gespeichert. <\/p>\n<p>Und - nein - sie stimmen nicht direkt \u00fcberein (das w\u00e4re irgendwie am Thema vorbei) <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" style=\"\" alt=\"L\u00e4cheln\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/wlEmoticon-smile-2.png\">), m\u00fcssen sie weiterverarbeitet werden, um die Anmeldedaten des Benutzers bzw. den Zugang des Pis zu validieren. <\/p>\n<p>Durch das L\u00f6schen des API-Schl\u00fcssels werden auch die MQTT-Anmeldeinformationen f\u00fcr einen bestimmten Pi gel\u00f6scht. <\/p>\n<h2>picockpit-Frontend<\/h2>\n<p>Das picockpit Frontend basiert nun auch beim Rendering zunehmend auf JavaScript. <\/p>\n<p>Es wurde beschlossen, PiCockpit mehr in Richtung einer SPA (Single Page Application) zu entwickeln. <\/p>\n<p>Eine weitere Integration der Seiten, die derzeit vom Backend gerendert werden, wird sp\u00e4ter in das Frontend erfolgen. <\/p>\n<p>Wir verwenden <a href=\"https:\/\/vuejs.org\/\">Vue.js<\/a> und <a href=\"https:\/\/vuetifyjs.com\/en\/\">Vuetify.js<\/a>und einige andere Bibliotheken f\u00fcr das Frontend, darunter Paho f\u00fcr die MQTT-Verbindung \u00fcber Websockets.<\/p>\n<p>Je nachdem, welchen Pi Sie gerade betrachten, abonniert das Webfrontend die entsprechenden MQTT-Pfade.<\/p>\n<p>Wenn Sie z.B. den \"shutdown\"-Button dr\u00fccken, wird eine Nachricht auf einem definierten MQTT-Pfad ver\u00f6ffentlicht, auf dem der picockpit-client lauscht.<\/p>\n<h3>Sicherheitsmerkmale<\/h3>\n<p>Das Frontend erzwingt die Verwendung einer HTTPS-Verbindung. \u00c4hnlich wie beim picockpit-Client werden die Daten \u00fcber Websockets ausschlie\u00dflich \u00fcber verschl\u00fcsselte Verbindungen an den Broker \u00fcbertragen (https:\/\/). <\/p>\n<p>In PiControl wird das Ausf\u00fchren von \"gef\u00e4hrlichen\" Aktionen wie Neustart oder Herunterfahren durch zus\u00e4tzliche Best\u00e4tigungsdialoge gesch\u00fctzt:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/image-94.png\"><img loading=\"lazy\" decoding=\"async\" width=\"315\" height=\"178\" title=\"Bild\" style=\"display: inline; background-image: none;\" alt=\"Bild\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2020\/10\/image_thumb-93.png\" border=\"0\"><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Ich wurde gebeten, ein wenig \u00fcber die Sicherheits- und Technologiegrundlagen von PiCockpit zu berichten. Die beteiligten Teile PiCockpit besteht aus mehreren Teilen: picockpit-client picockpit-frontend picockpit-backend picockpit-api (\"papi\") die Datenbank der MQTT Server das picockpit Package Repository der MQTT Server Der Datenaustausch zwischen picockpit-frontend und picockpit-client erfolgt \u00fcber den MQTT Server (genannt...<\/p>","protected":false},"author":830,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[432],"tags":[930,531,599,434,931,932,933,273],"class_list":["post-27844","post","type-post","status-publish","format-standard","hentry","category-picockpit","tag-how-does-it-work","tag-mongodb","tag-mqtt","tag-picockpit","tag-privacy","tag-protection","tag-safe-web-interface-for-the-raspberry-pi","tag-security"],"_links":{"self":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/27844","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/users\/830"}],"replies":[{"embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/comments?post=27844"}],"version-history":[{"count":1,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/27844\/revisions"}],"predecessor-version":[{"id":27845,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/27844\/revisions\/27845"}],"wp:attachment":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/media?parent=27844"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/categories?post=27844"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/tags?post=27844"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}