0%

Was schiefgehen kann

Schutzgüter, Angreifer und Vertrauensgrenzen

Jeder Test, den du in with Python geschrieben hast, stellt dieselbe Art von Frage: Bekommt die richtige Anfrage die richtige Antwort? Eine Anmeldung mit dem richtigen Passwort bekommt eine . Ein Schreibzugriff mit einem gültigen Token ändert ein Buch. Sicherheit fragt nach all den anderen Anfragen und nach Leuten, die nie eine senden.

Um das geordnet zu fragen, brauchst du drei : was der Dienst enthält, das jemand haben wollen würde, wer dieser Jemand sein könnte und wo seine Daten hereinkommen.

Was es wert ist, genommen oder geändert zu werden

Alles, was die Leseliste weiß, steht in state. Es hat vier Teile, die hier zählen, und ein Angreifer will von jedem etwas anderes. Dieser Block verwendet eine kleine Kopie des Zustands:

Try it

Die Bücher sind der Grund, warum es den Dienst gibt, und der Schaden dort ist eine Änderung: ein Buch, das von jemandem bearbeitet oder gelöscht wird, der das nicht können sollte. Die anderen drei sind anders. Hier beginnt der Schaden mit einem Lesen, denn jedes davon kann benutzt werden, sobald jemand es hat. Ein Passwort meldet an. Ein Token schreibt. Eine Session-ID ist eine Anmeldung, die schon stattgefunden hat. Eines davon zu ändern wäre auch ein Schaden, aber keine Route auf diesem Server ändert ein Passwort oder ein Token, also beginnt ein Angreifer mit dem Lesen.

Was ein Dienst enthält und was es ist, geschützt zu werden, nennt man seine Schutzgüter (assets). Es gibt ein fünftes, das gar nicht in state steht: dass der Dienst da ist, wenn seine Benutzer ihn brauchen. Kapitel 6 kommt darauf zurück.

Wer fragt

Über einen Angreifer lässt sich leichter nachdenken, wenn du ihn danach bestimmst, was er erreichen kann, nicht danach, wie schlau er ist. Drei reichen für diesen Kurs.

Ein Fremder im Netzwerk hat kein Konto. Er kann beliebige Bytes an jede Route senden, so oft er will, und er sieht die Antworten. Wenn der Dienst über einfaches HTTP läuft und der Fremde irgendwo auf dem Weg zwischen einem Benutzer und dem Server sitzt, kann er auch lesen, was dieser Benutzer sendet. Networks with Python hat diesen Beobachter auf dem Weg gezeigt und als Antwort darauf. Kapitel 10 kommt darauf zurück.

Ein angemeldeter Leser hat ein Konto. Denk an ben: Er hat eine gültige Session und ein gültiges Token, und alles, was die Routen ihm anbieten, darf er benutzen. Er wird zum Angreifer, wenn er etwas will, das ana gehört.

Jemand mit einer Kopie der Daten spricht nie mit dem Server. Er hat eine Sicherungsdatei, einen Abzug des Zustands oder einen Laptop, der in einem Zug liegen geblieben ist. Er liest state direkt.

Jemand findet eine alte Sicherungsdatei mit den Daten der Leseliste. Welcher Angreifer ist das?

Wo Daten die Grenze überqueren

Sieh dir jetzt handle(request, state) mit diesen Angreifern im Kopf an. Seine zwei kommen von zwei sehr verschiedenen Orten.

Alles in request hat ein Client geschrieben: die , das Ziel, jeden Header, den Body. Der Server hat kein einziges Byte davon gewählt. Alles in state gehört dem Server selbst. Die Linie zwischen beiden ist eine Vertrauensgrenze (trust boundary): eine Stelle, an der Daten von einem Ort, den du nicht kontrollierst, an einen Ort gelangen, den du kontrollierst.

         outside                |            inside
                                |
 client --- request ----------> |  handle(request, state) <--> state
        <-- response ---------- |
                                |
                       the trust boundary

Der Client und das Netzwerk sind draußen, und state ist drinnen. Eine Anfrage überquert die Grenze nach innen. Der Adapter macht aus ihren Bytes das request, read_body() liest den Body unter seiner Größengrenze, und handle() entscheidet alles andere.

Hier ist der Teil von handle(), der ein Buch ausliefert, gekürzt:

elif len(segments) == 2 and segments[0] == "books":
    book_id = book_id_from(segments[1])
    refusal = None
    if method == "PUT" or method == "DELETE":
        refusal = write_error(request, state)
    ...
    elif method == "PUT":
        response = book_request_error(request)
        if response is None:
            response = replace_book(request, state, book_id)

Welche dieser Namen enthalten Daten von draußen? segments, denn es wurde aus dem Anfrageziel geschnitten. Ebenso book_id, das aus einem Segment gemacht wurde. write_error liest request["headers"], und replace_book liest den -Body: beides Daten von draußen. state["books"] sind die einzigen Daten von drinnen, die hier zu sehen sind. Dein Server behandelt die Daten von draußen hier bereits sorgfältig. Er prüft, dass das Token bekannt ist, dass das Segment eine Zahl ist und dass der Body ein gültiges Buch ist, und zwar alles, bevor er etwas ändert. Diese Gewohnheit hat jetzt einen Namen: Daten von draußen werden an der Grenze geprüft, bevor man ihnen vertraut.

Welcher Wert hat in handle() die Vertrauensgrenze überquert?

Die zweite Überquerung

Daten überqueren die Grenze auch in die andere Richtung. Eine Antwort trägt Daten von drinnen nach draußen zu einem Client. Dasselbe tut eine Zeile in einem Log und eine Sicherung. Jede davon ist eine Kopie von etwas, das der Server wusste, und liegt jetzt an einem Ort, den der Server nicht kontrolliert. Lektion 4 sieht sich an, was eine Sicherung dieses Dienstes verrät.

Dort lebt der dritte Angreifer. Jede Prüfung in handle() läuft, wenn eine Anfrage ankommt. Die Person mit einer Kopie der Daten sendet keine Anfrage, also läuft für sie keine dieser Prüfungen je.

Warum kann keine Prüfung in handle() den Angreifer aufhalten, der eine Kopie der Daten hat?

Ein Bedrohungsmodell

Du hast jetzt drei kurze Listen: die Schutzgüter, die Angreifer mit dem, was jeder erreichen kann, und die Grenze mit ihren zwei Überquerungen. Zusammen sind sie ein Bedrohungsmodell (threat model) der Leseliste. Dieses ist absichtlich klein und schlicht. Seine Aufgabe ist es, aufgeschrieben zu werden, damit sich eine Schwachstelle daran festmachen lässt: dieser Angreifer, über diese Grenze, erreicht dieses Schutzgut.

Die nächste Lektion tut genau das und macht aus einer vagen Sorge etwas, das du beheben kannst.