Wer darf sich verbinden?
Woher kommt diese Anfrage?
Der Server lehnt jetzt einen Punktezähler ohne das Token vor 101 ab, und er akzeptiert einen
Origin, und eine Seite von woanders
Jeder Handshake, den ein Browser sendet, trägt einen Origin-Header, der die Website der Seite nennt, die die Verbindung geöffnet hat, zum Beispiel Origin: https://quiz.example. Das Skript der Seite kann ihn nicht ändern; der Browser schreibt ihn.
Das ist wichtig, weil Browser https://quiz.example an und besucht dann in einem anderen Tab eine Seite auf irgendeiner anderen Website. Diese Seite führt new WebSocket("wss://quiz.example/score") aus. Der Browser schreibt den Handshake, und wenn die Website erlaubt hat, dass ihr Cookie mit Anfragen reist, die andere Websites starten, hängt der Browser es an. (Moderne Browser halten die meisten Cookies von solchen Anfragen zurück, sofern die Website nichts anderes gesagt hat; wie eine Website das sagt, liegt außerhalb dieses Kurses.) Der Quizserver sieht ein gültiges Login und öffnet eine Punktezähler-Verbindung, die jetzt die Seite der anderen Website steuert. Das nennt man Cross-Site WebSocket Hijacking.
Gewöhnliche Webanfragen haben eine Abwehr, die in den Browser eingebaut ist: Eine Seite kann eine Anfrage an eine andere Website senden, aber der Browser lässt sie die Antwort nicht lesen. WebSockets fallen nicht unter diese Regel. Sobald die Verbindung offen ist, kann die Seite, die sie geöffnet hat, jede Nachricht lesen und eigene senden.
Die Anzeigetafel ist in ihrer jetzigen Form nicht dafür anfällig, weil ihr Punktezähler-Token kein Cookie ist. Ein Token im Query-
Eine Seite auf einer anderen Website öffnet aus dem Browser eines angemeldeten Benutzers ein WebSocket zu deinem Server. Welchen Nachweis fügt der Browser dafür hinzu?
Eine Allowlist
Die Abwehr besteht darin, Origin zu lesen und Seiten abzulehnen, die du nicht kennst. Die Bibliothek erledigt das für dich mit einem weiteren serve:
serve(handler, "127.0.0.1", 0, origins=["https://quiz.example"])
Mit origins= wird ein Handshake, dessen Origin nicht in der 101 abgelehnt, und ebenso ein Handshake ganz ohne Origin. Der Test ist ein Enthaltenseinstest, ungefähr dieser:
origin = request.headers.get("origin")
if origin is None or origin not in ["https://quiz.example"]:
... # answer 403 instead of 101
In einem Lauf auf einem lokalen Computer, mit http://localhost:8000 als einzigem erlaubtem Origin: http://evil.example eine 403 mit dem Body Failed to open a WebSocket connection: invalid Origin header: http://evil.example.; einer ohne Origin bekam eine 403 mit Failed to open a WebSocket connection: missing Origin header.; und das aufgeführte Origin wurde durchgelassen. Ein fehlendes Origin wird ebenfalls abgelehnt, also lehnt ein Server mit Allowlist auch Skripte ab, die kein Origin senden, wie standardmäßig den Python-Client der Bibliothek, außer None steht in der Liste.
Anzeigetafel v3 baut diese Prüfung nicht ein: Ihr Token ist kein Cookie, also kann eine fremde Seite auf nichts mitfahren, was der Browser hinzufügt. Ein Server, der Punktezähler über ein Cookie identifiziert, bräuchte sie.
Diese 403 ist die, die Lektion 2 versprochen hat. Der Server weiß genau, woher diese Anfrage kam, und sagt trotzdem nein, also verlangt er keinen Nachweis. Dieselbe Anfrage noch einmal zu senden hilft nicht.
Dein Server erlaubt nur https://quiz.example, und ein Handshake kommt mit Origin: http://evil.example an. Was antwortet die Bibliothek?
Was Origin nicht kann
Origin ist nur ehrlich, weil Browser es schreiben. Jedes Programm, das kein Browser ist, schreibt jedes Origin, das es will, oder keins. Der Python-Client der Bibliothek aus Kapitel 6 sendet von einem Laptop irgendwo Origin: https://quiz.example, wenn du connect(url, origin="https://quiz.example") übergibst. Eine Allowlist schützt also die Benutzer von Browsern vor den Seiten anderer Websites. Den Server vor Skripten schützt sie überhaupt nicht. Das Token entscheidet weiterhin, wer Origin-Prüfung kann nur daneben stehen, es nie ersetzen.
Warum hält eine Origin-Allowlist ein Python-Skript nicht vom Werten ab?
wss://
Die kapernde Seite oben hat wss://quiz.example/score verwendet. wss:// verhält sich zu ws:// wie https:// zu http://: derselbe Handshake und dieselben wss://-Verbindung öffnen, und der Server muss weiterhin das Token prüfen und, für Browser, das Origin.
Dieser Kurs betreibt seine Server auf ws:// und richtet nie TLS ein. Eine echte Anzeigetafel im Internet würde wss:// verwenden, denn ein unverschlüsselt gesendetes Token kann jeder unterwegs lesen.
Anzeigetafel v3 fehlt noch ein Stück. Ein Tippfehler eines Punktezählers schließt weiterhin seine Verbindung; das Projekt verwandelt diese Fehler in Antworten und prüft, dass das Token in keiner Antwort erscheint.