Warum ein Fehler nicht alles zerstören darf
Sichere Softwareentwicklung heißt, ein Programm von Anfang an so zu bauen, dass ein Fehler nur wenig Schaden anrichtet. Das ist wichtig, weil kein Programm fehlerfrei bleibt und Angreifende jeden Fehler suchen.
Stellen Sie sich einen Webshop vor. Er läuft mit allen Rechten, zeigt bei Fehlern interne Meldungen und glaubt jeder Anfrage. Ein einziger Tippfehler genügt dann für großen Schaden. Drei Entwurfsregeln verhindern das.
Am Ende dieser Lektion
Notiz
Ich kann grundlegende Regeln für einen sicheren Entwurf auf ein Programm anwenden.
Schlüsselwörter
| Begriff | Was er bedeutet |
|---|---|
| Vertrauensgrenze | die Linie zwischen Teilen eines Systems, denen Sie nicht gleich stark trauen; auf Englisch Trust Boundary |
| Geringste Rechte | jeder Teil bekommt nur die Rechte, die er braucht; auf Englisch Least Privilege |
| Sicherer Ausfall | bei einem Fehler endet das Programm im sicheren Zustand; auf Englisch Fail Safe |
| Angriffsfläche | alle Stellen, an denen jemand von außen etwas senden kann |
| Eingabe | alles, was ein Mensch oder ein anderes System an ein Programm sendet |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Eine Vertrauensgrenze trennt ungleich vertraute Teile
Eine Vertrauensgrenze ist eine Linie zwischen zwei Teilen eines Systems, denen Sie nicht gleich stark trauen. Daten, die diese Linie überqueren, prüfen Sie.
Alles, was ein Besucher tippt, kommt von außen und ist fremd. Das Programm darf es nicht für gut halten, nur weil es nun in seinem eigenen Speicher liegt.
Beispiel: Datenflüsse im Shop
| Datenfluss | Von | Nach | Grenze? |
|---|---|---|---|
| Suchwort tippen | Besucher (außen) | Shop-Programm | Ja: hier wird geprüft |
| Abfrage senden | Shop-Programm | Datenbank | Ja: nur geprüfte Werte gehen weiter |
| Zeile ins Protokoll | Shop-Programm | Protokolldatei | Nein: gleiche Zone |
| Preise anzeigen | Shop-Programm | Besucher (außen) | Ja: nur zeigen, was erlaubt ist |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Die eine Regel
Warnung
Dieses Lab ist ein Shop, der absichtlich unsicher ist. Sehen Sie nur Ihre eigene, private Kopie an und nichts sonst. Sie hat keine Verbindung ins Internet. Dieselben Versuche bei einem fremden System sind eine Straftat.
Eine Eingabe überquert die Grenze
curl -s -G --data-urlencode "q=pen" http://app:8000/searchHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Eine Adresse, die es nicht gibt
curl -s http://app:8000/nothingHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Was die beiden Ausgaben zeigen
Die erste Ausgabe ist Pen 1.2: Das Suchwort ging über die Grenze, und der Shop antwortete mit Name und Preis. Die zweite ist not found: Der Shop lehnt eine unbekannte Adresse knapp ab.
Beides sind Eingaben von außen. Jede Adresse und jedes Suchfeld gehört zur Angriffsfläche des Shops.
Jeder Teil bekommt nur nötige Rechte
Nach dem Prinzip der geringsten Rechte darf jeder Teil nur das, was seine Aufgabe verlangt. Eine Suche muss lesen, aber nie löschen.
So bleibt ein Fehler klein. Übernimmt jemand die Suche, kann er mit ihren Rechten nur suchen. Mit Administratorrechten könnte er alles ändern.
Rechte pro Rolle
RECHTE = {
"besucher": ["suchen"],
"mitarbeit": ["suchen", "preis_aendern"],
"admin": ["suchen", "preis_aendern", "nutzer_loeschen"],
}
def darf(rolle, aktion):
if rolle not in RECHTE:
return False
return aktion in RECHTE[rolle]
# Ändern Sie die Rolle in "besucher" und führen Sie den Block aus.
rolle = "mitarbeit"
print(rolle, "darf nutzer_loeschen:", darf(rolle, "nutzer_loeschen"))
print(rolle, "darf suchen:", darf(rolle, "suchen"))
Unter welchem Konto läuft der Shop?
Der Shop des Labs läuft in einem Container. Der nächste Run fragt, unter welcher Benutzernummer sein Prozess arbeitet. Die Antwort ist 65532: ein gewöhnliches Konto ohne besondere Macht.
Das ist geringste Rechte in der Praxis. Wer diesen Prozess übernähme, bekäme keine Administratorrechte.
Die Benutzernummer des Shops
docker exec app id -uHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein häufiger Fehler
Warnung
Viele glauben, ein interner Teil brauche keine Prüfung, weil nur das eigene Programm ihn aufruft. Das stimmt nicht. Ein Fehler oder ein Angriff an einer Stelle erreicht sonst alle anderen. Prüfen Sie jede Eingabe an jeder Vertrauensgrenze, auch zwischen eigenen Teilen.
Im Zweifel ablehnen: der sichere Ausfall
Ein Programm kann immer an einen Fehler geraten. Der sichere Ausfall legt fest, was dann geschieht: Das Programm lehnt ab und zeigt keine Einzelheiten.
Der schlechte Entwurf erlaubt im Zweifel. Dann reicht ein unbekanntes Konto oder ein Absturz, und die Prüfung lässt jeden durch.
Zwei Entwürfe für denselben Fehlerfall
RECHTE = {"besucher": ["suchen"], "admin": ["suchen", "loeschen"]}
def darf_loeschen_schlecht(rolle):
try:
return "loeschen" in RECHTE[rolle]
except KeyError:
return True
def darf_loeschen_gut(rolle):
try:
return "loeschen" in RECHTE[rolle]
except KeyError:
return False
# Ändern Sie die Rolle in "admin" und führen Sie den Block aus.
rolle = "praktikant"
print("schlecht:", darf_loeschen_schlecht(rolle))
print("gut:", darf_loeschen_gut(rolle))
Auch die Fehlermeldung gehört zum Entwurf
Der nächste Run sucht einen Namen mit Apostroph. Der Shop kann ihn nicht verarbeiten und antwortet mit einer Zeile, die mit database error beginnt. Danach folgt ein Stück Meldung der Datenbank.
Prüfen Sie Ihr Urteil: Besucher brauchen diese Einzelheiten nicht. Sie verraten Fremden, wie der Shop gebaut ist.
Was der Shop bei einem Fehler zeigt
curl -s -G --data-urlencode "q=Baker's" http://app:8000/searchHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.