📱 Hey Siri Kurzbefehle, Apple Shortcuts -> SSH -> MQTT -> FHEM, Access Control

Begonnen von Torxgewinde, 12 Mai 2023, 22:03:57

Vorheriges Thema - Nächstes Thema

Torxgewinde

"Hey Siri, schalte die Gartenbeleuchtung ein" - ohne Homekit

Siri Kurzbefehle sind in iOS Geräten eine komfortable Option, um mittels Widgets oder auch mit der "Hey Siri" Sprachsteuerung Befehle auszuführen. Einer der Kurzbefehle erlaubt es SSH Befehle auszuführen, was einem viele weitere Schnittstellen ermöglicht.

Da die iOS Geräte zwar schon recht sicher sind, aber trotzdem einen Angriffsvektor darstellen, ist es nicht ratsam, direkt die Befehle an FHEM oder die Konsole weiterzugeben. Zu einfach wäre es, einen schädlichen Befehl abzusetzen.

Als Schnittstelle zwischen Apple-Gerät (iPhone, Mac, iPad) kommt SSH aus einem Kurzbefehl zum Einsatz. Empfangen wird der Befehl von einem SSH Daemon. Als SSH Daemon reicht bereits etwas minimales wie Dropbear auf einem System wie z.B. OpenWRT. Damit man mit SSH nicht auf dem Server beliebige Befehle ausführen kann, wird ein Nutzer erstellt, der wenig Rechte im System hat, und es wird mit "forced_command" nur ein einziges Programm erlaubt. Dieses erlaubte Programm ist hier ein Shell-Skript, welches die Daten dann an FHEM weitergibt. In diesem Fall habe ich die Daten noch über MQTT verschickt und dann erst in FHEM mit einem Device bearbeitet. Damit in FHEM nicht jeder Befehl ausgeführt wird, gibt es eine Whitelist von regulären Ausdrücken - so kann dann das Apple-Gerät nur genau diese Befehle ausführen.

Erstmal benötigt man die App "Kurzbefehle" bzw. "Shortcuts" von Apple.

Dann erstellt man sich einen Shortcut mit dem SSH Befehl. Extra ein Shortcut anzulegen bietet den Vorteil, nur an einer Stelle den SSH Zugriff einstellen zu müssen.
Du darfst diesen Dateianhang nicht ansehen. Du darfst diesen Dateianhang nicht ansehen.

Nun erstellt man sich seine Shortcuts für Aktionen, hier schalten wir ein Radio mit einer Funkschaltsteckdose ein:
Du darfst diesen Dateianhang nicht ansehen.Du darfst diesen Dateianhang nicht ansehen.
Der Name des Shortcut ist auch gleichzeitig der Sprachbefehl.

Zu dem SSH Daemon, Dropbear oder analog auch OpenSSH:
Es wird ein Nutzer angelegt, der wenig Rechte im System hat. Das geht zum Beispiel bei einem OpenWRT System in der Art (Doku dazu):
opkg update
opkg install shadow-useradd
useradd appleshortcut
passwd appleshortcut
--> Passwort festlegen

mkdir -p /home/appleshortcut
chown appleshortcut /home/appleshortcut
vi /etc/passwd
---> Die gewünschte Shell ergänzen (ganz hinten)
---> appleshortcut:x:1000:1000::/home/appleshortcut:/bin/ash

/etc/init.d/dropbear restart

Nun hat man also einen User "appleshortcut", der seine Dateien im Ordner "/home/appleshortcut" findet und der sich mit SSH auf Port 22 einloggen kann. Nun macht es Sinn, diesen SSH Zugriff nicht so universell zu gestalten - der User soll ja nur ganz bestimmte FHEM Befehle absetzen können, mehr nicht. Das gelingt, indem man dem SSH Daemon den Zugriff mit Passwörtern verwehrt, was mit der LuCI-Weboberfläche recht einfach ist:
Du darfst diesen Dateianhang nicht ansehen.

Von nun an gelingt der SSH Zugriff nur noch mit SSH-Schlüsseln. Dem jeweiligen fremden System teilt man den öffentlichen Schlüssel mit, anhand dem man authentifiziert wird. Das ist eh sicherer als ein Passwort, da die Schlüssel länger bzw. schwerer zu erraten sind.

Den öffentlichen Schlüssel vom Kurzbefehl vom iOS Gerät braucht man gleich. Den kann man aus den Details kopieren, wenn man sich den SSH Kurzbefehl anschaut:
Du darfst diesen Dateianhang nicht ansehen.

Damit der SSH Daemon einen Nutzer anhand des Schlüssels authentifiziert, legt man eine Datei an unter "/home/appleshortcut/.ssh/authorized_keys" mit folgendem Inhalt:
no-port-forwarding,no-X11-forwarding,no-pty,command="sh script.sh" ssh-ed25519 hier_den_öffentlichen_Schlüssel_vom_iOS_Gerät Kommentar_zum_GerätGemäß der Doku haben wir also recht viele Beschränkungen hinzugefügt und den öffentlichen Schlüssel in diese Datei kopiert. Die wichtigste Beschränkung ist, dass nur noch ein Skript ausgeführt wird und keine universelle Shell. Das Skript heißt kreativerweise "script.sh" und liegt hier unter "/home/appleshortcut/script.sh". Es hat folgenden Inhalt:
#!/bin/sh

mosquitto_pub -t "AppleShortcut" -m "$SSH_ORIGINAL_COMMAND" -h brokeradresse -u nutzername -P geheimes_passwort

So, nun landen Befehle schon mal in unserem MQTT Broker. Es ist übrigens sinnvoll, den Broker auch TLS zu verschlüsseln, falls dieser auf einem anderen Gerät läuft, aber das habe ich jetzt mal weggelassen. Jetzt kann FHEM auf dieses MQTT Topic reagieren. Dafür kann man ein Device definieren:


defmod AppleShortcut.device MQTT2_DEVICE
attr AppleShortcut.device IODev Mosquitto
attr AppleShortcut.device alias Apple Shortcut
attr AppleShortcut.device devicetopic AppleShortcut
attr AppleShortcut.device icon logo_apple
attr AppleShortcut.device readingList $DEVICETOPIC:.* { my $ret=json2nameValue($EVENT);; $ret->{state}=lc($ret->{action}) if (defined($ret->{action}));; return $ret }
attr AppleShortcut.device stateFormat {\
    my @ts = ReadingsTimestamp($name,"state","") =~ /^(\d+)-(\d+)-(\d+)\s(\d+:\d+):(\d+)$/;;\
    my $value = ReadingsVal($name, "action", "???");;\
    \
    return "<b>$value</b><br \><small>($ts[2].$ts[1].$ts[0] - $ts[3]:$ts[4])</small>";;\
}
attr AppleShortcut.device userReadings action_result:action.* {\
    my $value = ReadingsVal($name, "action", "???");;\
    my $response = "nok";;\
\
    ## Liste von erlaubten Befehlen als regulärer Ausdruck\
    ##   Zeilenende $ und Anfang ^ mit beachten,\
    ##   sonst sind unbeabsichtigte Befehlsketten/Escapes möglich\
    my @commands = (\
        '^set SteckdoseKuechenradio\.device o(?:ff|n)$',\
        '^set G\.Ding1 on-for-timer [0-9]+$',\
        '^set G\.Ding2 o(?:ff|n)$'\
    );;\
    \
    ##wandel von String in RegEx um\
    @commands = map { qr{$_} } @commands;;\
\
    ##behalte was matcht, speichere die Arraylänge\
    my $match = scalar grep { $value =~ $_ } @commands;;\
\
    if ($match) {\
        fhem("$value");;\
        $response = "ok";;\
    }\
\
    return "$response";;\
}

In diesem Define ist als UserReading die Reaktion auf MQTT Telegramme hinterlegt. Was erlaubt ist, wird mit dem Array @command spezifiziert. Es ist eine Liste von Strings mit regulären Ausdrücken.

Die Verzögerung vom Starten eines Befehls, bis zur Ausführung beträgt ca. 500ms bis 2s.

Mit den Tipps kann man mit Siri -> Kurzbefehle -> SSH -> MQTT -> FHEM steuern. Alternativ, falls man MQTT nicht in dieser Kette nutzen möchte, kann man in dem "script.sh" auch direkt fhem.pl aufrufen, sofern es auf dem gleichem System läuft. Dann sollte man in dem Skript die Whitelist einfügen und die Kommandos entsprechend mit Shell-Befehlen prüfen.