CORS und CCU – lighttpd: Error 510 bei OPTIONS-Anfragen

Einrichtung, Nutzung und Hilfe zu RaspberryMatic (OCCU auf Raspberry Pi)

Moderatoren: jmaus, Co-Administratoren

Karamike
Beiträge: 29
Registriert: 19.12.2021, 12:22
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 2 Mal

CORS und CCU – lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von Karamike » 31.12.2022, 19:33

In meinem Weihnachtsprojekt wollte ich (im Prinzip) den Wert einer RaspberryMatic-Systemvariablen mit einer Webanwendung anzeigen und verändern.

AFAIK kann man Systemvariable NICHT mit der XML-API setzen und lesen, sondern nur mit der Skript-API, indem man ein Skript-Snippet mit POST an Port 48181 sendet.

Von der Kommandozeile funktioniert das auch wie erwartet:

Code: Alles auswählen

curl -v --insecure -X POST --data 'x = dom.GetObject("SV_heizung").Value();' https://192.168.0.80:48181/regex.exe
Antwort:

Code: Alles auswählen

<xml><exec>/regex.exe</exec><sessionId></sessionId><httpUserAgent>user-agent: curl/7.68.0</httpUserAgent><x>20230108</x></xml>
Wenn das aus einer Webanwendung geschehen soll, kommt CORS (Cross-Origin Resource Sharing) ins Spiel, das die Auslieferung von der gleichen "Origin" verlangt.

Da der Port des Webservers lighttpd (http/https - 80 oder 443) nicht dem der Skript-API entspricht (48181), ist es nicht mehr "Same-Origin". Es hilft dabei auch nicht, dass der Javascript-Code der Webanwendung vom gleichen Raspberry-Webserver ausgeliefert wird.

Falls es sich nicht um "Same-Origin" handelt, erzeugt der Webbrowser einen sog. Preflight-Request: eine OPTIONS-Anfrage "Darf ich die Ressource von Dir laden?", die vor der eigentlichen Abfrage gesendet wird.

Wenn ich das entsprechende Protokoll richtig verstanden habe, gibt der Server über HTTP-Header "Allow-Control-Allow-*" sein OK oder eben nicht.

Der Server in RaspberryMatic erzeugt jedoch einen Fehler 510. Dabei hilft es dann auch nicht, dass ich lighttpd dazu gebracht habe die entsprechenden Header zu senden. Fehler bleibt Fehler. CORS bricht ab und es kommt nicht zur eigentlichen Datenabfrage.

Der Fehler zeigt sich auch mit einer OPTIONS-Abfrage von der Kommandozeile:

Code: Alles auswählen

curl -v --insecure -X OPTIONS https://192.168.0.80:48181/regex.exe

Code: Alles auswählen

*   Trying 192.168.0.80:48181...
* TCP_NODELAY set
* Connected to 192.168.0.80 (192.168.0.80) port 48181 (#0)
...
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
...
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
...
> OPTIONS /regex.exe HTTP/2
> Host: 192.168.0.80:48181
> user-agent: curl/7.68.0
> accept: */*
> 
...
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 8)!
< HTTP/2 510 
< accept-ranges: bytes
< cache-control: private, no-cache, must-revalidate, no-transform, max-age=0
< content-type: text/html; charset=iso-8859-1
< x-frame-options: SAMEORIGIN
< x-content-type-options: nosniff
< x-xss-protection: 1; mode=block
< x-robots-tag: none
< x-download-options: noopen
< x-permitted-cross-domain-policies: none
< referrer-policy: no-referrer
< access-control-allow-origin: https://192.168.0.80
< access-control-allow-methods: POST, GET, OPTIONS
< date: Sat, 31 Dec 2022 14:31:15 GMT
< 
...
Wie gesagt, die Header "access-control-allow-origin" und "access-control-allow-methods" habe ich lighttpd per Config "aufgezwungen".

Die Beschreibung des Web-Fehlers 510 (Not Extended) legt auch nicht gerade nahe, was schief läuft.

URLs deren OPTIONS mit 510 beantwortet werden:

Code: Alles auswählen

https://192.168.0.80
https://192.168.0.80/
https://192.168.0.80/login.html
OPTIONS mit OK-Status 200

Code: Alles auswählen

https://192.168.0.80/addons/cuxd/
https://192.168.0.80/addons/cuxd/robots.txt
Hat jemand eine Idee, wie man lighttpd dazu bringen kann, die OPTIONS anfrage positiv zu beantworten?

Frohes Neues...

Michael

McPan
Beiträge: 194
Registriert: 29.11.2021, 07:04
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 10 Mal
Danksagung erhalten: 37 Mal

Re: lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von McPan » 01.01.2023, 09:54

Karamike hat geschrieben:
31.12.2022, 19:33

Code: Alles auswählen

...
< access-control-allow-origin: https://192.168.0.80
...
Wie gesagt, die Header "access-control-allow-origin" und "access-control-allow-methods" habe ich lighttpd per Config "aufgezwungen".
...
Vielleicht für den Header auch einmal

Code: Alles auswählen

Access-Control-Allow-Origin: https://192.168.0.80:48181
(mit Portangabe, da https sonst Port 443 impliziert) eintragen, oder ggf. zum Testen auch einmal "*" angeben?
Grüße,
Marco

Elektrische Bauteile funktionieren mit Rauch. Der Beweis: tritt der Rauch aus, funktioniert das Bauteil nicht mehr!
Raspberrymatic @ RPi3b+, HmIP mit RPi-RF-MOD

Karamike
Beiträge: 29
Registriert: 19.12.2021, 12:22
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 2 Mal

Re: lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von Karamike » 01.01.2023, 12:47

McPan hat geschrieben:
01.01.2023, 09:54
(mit Portangabe, da https sonst Port 443 impliziert) eintragen, oder ggf. zum Testen auch einmal "*" angeben?
Danke für den Hinweis, aber ... alles schon probiert.

Das Problem im Augenblick scheint zu sein, dass lighttpd die OPTIONS-Anfrage mit einem Fehlercode 510 beantwortet. Und ich finde in der Konfiguration von lighttpd nichts, was ihn davon abhalten könnte.

Im Anhang ein Screenshot der Webconsole von Firefox.

Unten links sieht man, wie nach dem Laden von main-xxxx.js versucht wird, den POST abzusetzen. Dafür erzeugt der Browser die Preflight-OPTIONS-Anfrage, die fehlschlägt, sodass es gar nicht zum eigentlichen POST kommt.

Auf der rechten Seite erkennt man oben in lila den Fehlerstatus 510.

Darunter in den Antwortzeilen u.a. die "access-control-allow-*"-Header, die ich lighttpd untergeschoben habe.
Dateianhänge
cors510.png

McPan
Beiträge: 194
Registriert: 29.11.2021, 07:04
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 10 Mal
Danksagung erhalten: 37 Mal

Re: lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von McPan » 01.01.2023, 17:29

Hmm, wird der Origin-Header beim Preflight-OPTIONS-Request (nicht in der Antwort) denn auch gesetzt? Denke mal ja, sollte eigentlich automatisch erfolgen.
Grüße,
Marco

Elektrische Bauteile funktionieren mit Rauch. Der Beweis: tritt der Rauch aus, funktioniert das Bauteil nicht mehr!
Raspberrymatic @ RPi3b+, HmIP mit RPi-RF-MOD

Karamike
Beiträge: 29
Registriert: 19.12.2021, 12:22
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 2 Mal

Re: lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von Karamike » 04.01.2023, 21:53

McPan hat geschrieben:
01.01.2023, 17:29
Hmm, wird der Origin-Header beim Preflight-OPTIONS-Request (nicht in der Antwort) denn auch gesetzt? Denke mal ja, sollte eigentlich automatisch erfolgen.
Ja, der Origin-Header ist da. Ist leider im Bild oben nicht zu sehen.

Eine weitere Recherche hat ergeben, dass die Anfrage auf dem Port der Script-API (48181) zwar vom Webserver lighttpd entgegengenommen wird, der sie dann aber intern (via localhost) an einen Daemon auf Port 8183 weiterleitet. Vermutlich der Homematic-Script-Server.

Dieser scheint mit der OPTIONS-Anfrage nicht zurechtzukommen, sodass lighttpd einen Fehler zurück gibt, die selbst "untergeschobene" Access-Control-Header ungültig macht.

Ich nehme an, dass an ein CORS-Szenario beim Erstellen des Skript-Servers niemand gedacht hat, und der entsprechende Code schlicht und einfach fehlt.

mademyday
Beiträge: 206
Registriert: 03.10.2014, 12:46
System: CCU
Wohnort: Enzkreis
Hat sich bedankt: 2 Mal
Danksagung erhalten: 26 Mal

Re: lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von mademyday » 04.01.2023, 22:11

nach Portfreigabe gleich den :8183 ansprechen?
Zuletzt geändert von mademyday am 05.01.2023, 06:28, insgesamt 1-mal geändert.

Benutzeravatar
jmaus
Beiträge: 9063
Registriert: 17.02.2015, 14:45
System: Alternative CCU (auf Basis OCCU)
Wohnort: Dresden
Hat sich bedankt: 378 Mal
Danksagung erhalten: 1467 Mal
Kontaktdaten:

Re: lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von jmaus » 04.01.2023, 22:20

Karamike hat geschrieben:
04.01.2023, 21:53
Dieser scheint mit der OPTIONS-Anfrage nicht zurechtzukommen, sodass lighttpd einen Fehler zurück gibt, die selbst "untergeschobene" Access-Control-Header ungültig macht.

Ich nehme an, dass an ein CORS-Szenario beim Erstellen des Skript-Servers niemand gedacht hat, und der entsprechende Code schlicht und einfach fehlt.
Dann könntest du ja kurz mal darlegen was du denkst in dem Skript-Server geändert werden müsste um das entsprechend umzusetzen. Dann könnte ich mir das ggf. mal anschauen und vielleicht die fehlenden Dinge in dem Skript-Server (ReGaHss) entsprechend umsetzen.
RaspberryMatic 3.67.10.20230114 @ Proxmox – ~195 Hm-RF/HmIP-RF/HmIPW Geräte + ioBroker – GitHub / Twitter / Facebook / Sponsors

Karamike
Beiträge: 29
Registriert: 19.12.2021, 12:22
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 2 Mal

Re: lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von Karamike » 06.01.2023, 21:51

jmaus hat geschrieben:
04.01.2023, 22:20
Dann könntest du ja kurz mal darlegen was du denkst in dem Skript-Server geändert werden müsste um das entsprechend umzusetzen.
Das ist eine gute Frage. :-)

Der Script-Server als solches tut ja was er soll:

Der Befehl

Code: Alles auswählen

curl -v --insecure -X POST --data 'x = dom.GetObject("SV_heizung").Value();' https://192.168.0.80:48181/regex.exe
liefert das erwartete Ergebnis: den OK-Code 200 und im Body das XML mit dem Ergebnis.

Der Befehl

Code: Alles auswählen

curl -v --insecure -X OPTIONS https://192.168.0.80:48181/regex.exe
liefert hingegen den Fehlercode 510.

Der Grund, dass der Server überhaupt auf OPTIONS reagieren sollte liegt darin, dass dies gebraucht wird, wenn eine Webanwendung auf den Script-Server zugreifen soll (gleiches gilt wahrscheinlich für den XML-Server).

Selbst wenn die Webanwendung von dem Raspberry geladen wird, auf dem der Skript-Server läuft, ist der Port des Skript-Servers (48181) und der Port des Webservers (443) nicht identisch. Damit ist er nicht mehr "Same-Origin" und der Webbrowser auf dem die geladene Webandwendung läuft, schaltet eine OPTIONS-Anfrage an den 48181-Server vor (Preflight), bei der er nachfragt, ob die Anfrage zulässig ist.

Ein Fehler-Code auf diese OPTIONS-Anfrage wird als Ablehnung interpretiert. Das ist das, was im Augenblick passiert.

Was der Browser für CORS nun tatsächlich erwartet, kann ich mangels Testmöglichkeit nicht sagten. Ich kann nur auf die Dokumentation von Mozilla verweisen. So wie ich das sehe sind das wohl:

Return-Code: 204 (No Content)

Sowie die Rückgabe-Header:

Access-Control-Allow-Origin

mit den Werten "*" oder dem Origin (inkl. Schema + Port)

und

Access-Control-Allow-Methods

in diesem Fall wohl mit den Werten "OPTIONS, POST" (da wir ja nur diese beiden Verben hier brauchen).

Noch ein Hinweis zu den sog. "simple requests". Es gibt Requests (auch POST-Abfragen), bei denen ein CORS-Preflight nicht ausgelöst wird. Diese Abfragen unterliegen diversen Einschränkungen, auch was die verwendeten Headern angeht.

Der Header "Authorization" löst aber mit Sicherheit den CORS-Preflight aus.

Wie und ob der Skript-Server dies an den lighttpd-Server zurückgeben kann, weiß ich nicht.

Benutzeravatar
jmaus
Beiträge: 9063
Registriert: 17.02.2015, 14:45
System: Alternative CCU (auf Basis OCCU)
Wohnort: Dresden
Hat sich bedankt: 378 Mal
Danksagung erhalten: 1467 Mal
Kontaktdaten:

Re: lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von jmaus » 06.01.2023, 23:24

Karamike hat geschrieben:
06.01.2023, 21:51
Der Befehl

Code: Alles auswählen

curl -v --insecure -X OPTIONS https://192.168.0.80:48181/regex.exe
liefert hingegen den Fehlercode 510.

Der Grund, dass der Server überhaupt auf OPTIONS reagieren sollte liegt darin, dass dies gebraucht wird, wenn eine Webanwendung auf den Script-Server zugreifen soll (gleiches gilt wahrscheinlich für den XML-Server).
Hast du mal ein Beispiel einer solchen Webanwendung parat zur Hand? Vielleicht als Pythonanwendung oder ähnlich damit ich das selbst hier reproduziert bekomme. Dann könnte ich mir das in einer ruhigen Minute mal anschauen, auch um zu verstehen um was es hier denn genau geht, denn ehrlich gesagt durchschau ich diese ganze CORS und OPTIONS Problematik noch nicht ganz, denn davon höre ich gerade zum ersten mal.
RaspberryMatic 3.67.10.20230114 @ Proxmox – ~195 Hm-RF/HmIP-RF/HmIPW Geräte + ioBroker – GitHub / Twitter / Facebook / Sponsors

Karamike
Beiträge: 29
Registriert: 19.12.2021, 12:22
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 2 Mal

Re: lighttpd: Error 510 bei OPTIONS-Anfragen

Beitrag von Karamike » 07.01.2023, 17:12

jmaus hat geschrieben:
06.01.2023, 23:24
Hast du mal ein Beispiel einer solchen Webanwendung parat zur Hand? Vielleicht als Pythonanwendung oder ähnlich damit ich das selbst hier reproduziert bekomme.
Hallo Jens,

eine Webanwendung läuft in Deinem Browser und ist daher meist in JavaScript geschrieben. Und es ist der Browser, der CORS (Cross-Origin Resource Sharing) implementiert, da er merkt, dass der Port der Website, von dem er die Seite mit dem JavaScript heruntergeladen hat, und der Port der Abfrage an den Skript-Server, unterschiedlich sind (Verstoß gegen Same-Origin).

Der Sinn des CORS-Schutzes ist vielleicht eher zu verstehen, wenn man es als Schutz eines fremden Servers begreift. Es reichen aber schon unterschiedliche Ports auf dem gleichen Server.

Um trotzdem eine Abfrage zu ermöglichen, fragt der Webbrowser (!) diese zweite Site, ob er die Daten dort anfordern darf. Das macht er mit einer OPTIONS-Anfrage. Diese zweite Site ist in unserem Fall der Skript-Server auf Port 48181.

Um es nochmals klar zu sagen: Der CORS-Schutz ist eine "Erfindung" des Webbrowsers, mit dem man sich nur deshalb herumschlagen muss, weil das Webanwendungs-JavaScript in diesem Browser läuft.
Ein Python-Programm, das außerhalb des Webbrowsers ausgeführt wird, kennt kein CORS, und hat diese Probleme deshalb nicht.

Wie gewünscht im Anhang ein kleines JavaScript-Programm mit vielen Kommentaren, sodass es eigentlich von jedem Coder verstanden werden sollte. Ich musste es ZIPen, um es hier hochladen zu können.

Dieses Bild zeigt das erwartete Ergebnis:
erwartet.png
  • Ergebnis 1: Unveränderter ursprünglicher Text aus der HTML-Datei.
  • Ergebnis 2: Per JavaSkript geänderter Text, bei dem Tags aber "ausgeführt" werden.
  • Ergebnis 3: Per JavaSkript geänderter Text, bei dem die Tags aber zu sehen sind.
  • Ergebnis 4: Per JavaSkript geänderter Textinhalt, wobei der Text das Ergebnis der Abfrage des Skript-Servers ist.

Dieses Bild zeigt das tatsächliche Ergebnis.
cors_fehler.png
Im abgedunkelten Bereich sieht man, dass bei "Ergebnis 4" nichts verändert wurde. Das entsprechende JavaScript wurde durch den Fehler vorzeitig beendet.

Im unteren Teil (die Developer-Konsole - in Firefox mit F12 erreichbar) sieht man sehr schön, wie der Webbrowser (!) vor dem POST eine OPTIONS-Anfrage eingefügt hat (sie steht nicht im Programm).
Ein paar Zeilen tiefer sieht man auch den Status-Code 510, der diesem Thread seinen Namen gegeben hat.

Um die HTML-Datei vom Raspberry ausliefern zu lassen, habe ich eine Link aus dem CUXD-Verzeichnis zu einem Verzeichnis auf dem angesteckten USB-Stick erzeugt, um die interne SD-Karte zu schonen. Diese Datei ist dann mit einer entsprechenden URL erreichbar.

Und ja, das Bild "erwartetes Ergebnis" stammt aus einem Workaround (Freigabe von "POST /regex.exe" über alle Ports (in lighttpd.conf). Gleicher Port -> kein CORS -> Problem umgangen). Ich weiß, hält nur bis zum nächsten Firmware-Update...

Beste Grüße

Michael
Dateianhänge
beispiel.zip
(1.15 KiB) 2-mal heruntergeladen

Antworten

Zurück zu „RaspberryMatic“