Lektion 8.3

Webtechnik: HTML, CSS und Formulare

19 min Lesezeit

Für das Schulfest gibt es eine Anmeldeseite. Du tippst deinen Namen ein, klickst auf „Anmelden“, und kurz danach steht er in der Liste der Organisatorin. Was passiert dazwischen? Wie kommen die Eingaben zum Server, und wie landen sie in einer Datenbank, ohne dass jemand sie beschädigen kann?

HTML und CSS kennst du aus der Mittelstufe. Hier gehst du genauer vor: Aufbau einer Seite, Layout mit Raster, Formulare, Seiten aus einer Datenbank und die Anmeldung von Nutzern.

Definition

HTML5: Grundgerüst, Elemente, Attribute und Hyperlinks

HTML beschreibt die Struktur einer Seite durch Elemente. Ein Element besteht aus Anfangs-Tag, Inhalt und End-Tag, zum Beispiel <p>Text</p>\texttt{<p>Text</p>}. Manche Elemente haben keinen Inhalt, etwa <meta>\texttt{<meta>} und <input>\texttt{<input>}. Attribute stehen im Anfangs-Tag als Paare name="wert"\texttt{name="wert"} und bestimmen das Element näher. Jede HTML5-Seite hat dieses Grundgerüst:

ZeileEinrückungAnweisung
10<!DOCTYPE html>\texttt{<!DOCTYPE html>}
20<html lang="de">\texttt{<html lang="de">}
31<head>\texttt{<head>}
42<meta charset="utf-8">\texttt{<meta charset="utf-8">}
52<title>Schulfest</title>\texttt{<title>Schulfest</title>}
61</head>\texttt{</head>}
71<body>\texttt{<body>}
82<h1>Schulfest</h1>\texttt{<h1>Schulfest</h1>}
92<p>Mehr im <a href="programm.html">Programm</a>.</p>\texttt{<p>Mehr im <a href="programm.html">Programm</a>.</p>}
101</body>\texttt{</body>}
110</html>\texttt{</html>}

Zeile 1 meldet HTML5. Das Element html\texttt{html} enthält head\texttt{head} mit Angaben über die Seite (Zeichensatz, Titel im Tab) und body\texttt{body} mit dem sichtbaren Inhalt. Ein Hyperlink ist das Element a\texttt{a}. Sein Attribut href\texttt{href} nennt das Ziel.

Definition

Dokumentbaum

Der Browser liest den Text und baut daraus den Dokumentbaum (DOM). Jedes Element ist ein Knoten und liegt in genau einem Elternelement. Elemente im selben Elternelement sind Geschwister. Die Wurzel ist html\texttt{html}. CSS und Skripte greifen über den Baum auf Elemente zu. Für das Gerüst oben (ohne die Textknoten) gilt:

ElementLiegt direkt in
htmlWurzel
head, bodyhtml
meta, titlehead
h1, pbody
ap

Es sind 8 Elemente.

Beispiel

Wohin führt der Link?

Die Seite liegt unter https://schule.example/fest/index.html. Wohin führen die Werte href="programm.html"\texttt{href="programm.html"}, href="../start.html"\texttt{href="../start.html"} und href="#anmeldung"\texttt{href="\#anmeldung"}?

Ein Pfad ohne Protokoll ist relativ zur Adresse der aktuellen Seite.

  • programm.html\texttt{programm.html} steht im selben Ordner: https://schule.example/fest/programm.html.
  • ../start.html\texttt{../start.html} geht einen Ordner nach oben: https://schule.example/start.html.
  • #anmeldung\texttt{\#anmeldung} bleibt auf derselben Seite und springt zum Element mit id="anmeldung"\texttt{id="anmeldung"}.

Ein absoluter Link enthält die ganze Adresse mit Protokoll.

Definition

CSS3: Selektoren und Kaskade

CSS trennt das Aussehen von der Struktur. Eine Regel hat die Form selektor { eigenschaft: wert; }\texttt{selektor \{ eigenschaft: wert; \}}. Der Selektor wählt Elemente aus:

  • p\texttt{p} wählt alle Elemente p\texttt{p} (Typselektor).
  • .hinweis\texttt{.hinweis} wählt Elemente mit class="hinweis"\texttt{class="hinweis"} (Klasse, mehrfach verwendbar).
  • #kopf\texttt{\#kopf} wählt das Element mit id="kopf"\texttt{id="kopf"} (die ID gibt es auf einer Seite nur einmal).
  • nav a\texttt{nav a} wählt alle a\texttt{a}, die irgendwo in einem nav\texttt{nav} liegen. ul > li\texttt{ul > li} wählt nur li\texttt{li}, die direkt in einem ul\texttt{ul} liegen.
  • a:hover\texttt{a:hover} wählt einen Link, über dem die Maus steht (Pseudoklasse).

Treffen mehrere Regeln ein Element mit verschiedenen Werten, gewinnt die spezifischere: ID vor Klasse und Pseudoklasse vor Typ. Bei gleicher Spezifität gilt die spätere Regel. Manche Eigenschaften, etwa die Schriftfarbe, erben Kinder vom Elternelement. Hat ein p\texttt{p} die Klasse hinweis\texttt{hinweis} und die ID kopf\texttt{kopf}, schlägt #kopf { color: green; }\texttt{\#kopf \{ color: green; \}} die Regeln .hinweis { color: red; }\texttt{.hinweis \{ color: red; \}} und p { color: navy; }\texttt{p \{ color: navy; \}}.

Definition

CSS3: Grid-Layout

Mit display: grid\texttt{display: grid} wird ein Container zum Raster. grid-template-columns\texttt{grid-template-columns} legt die Spalten fest, grid-template-rows\texttt{grid-template-rows} die Zeilen. Maße sind feste Größen (100px\texttt{100px}) oder Anteile (1fr\texttt{1fr}): Ein Anteil ist ein Teil des Platzes, der nach Abzug der festen Größen und der Abstände (gap\texttt{gap}) übrig bleibt. Kindelemente füllen die Zellen der Reihe nach. Mit grid-column: 1 / 3\texttt{grid-column: 1 / 3} reicht ein Element von Spaltenlinie 1 bis 3, also über zwei Spalten.

Beispiel

Spaltenbreiten im Raster

Ein Container ist 940 Pixel breit und hat grid-template-columns: 100px 1fr 3fr\texttt{grid-template-columns: 100px 1fr 3fr} sowie gap: 20px\texttt{gap: 20px}. Wie breit sind die drei Spalten?

Bei drei Spalten gibt es zwei Abstände: 2 · 20 = 40 Pixel. Für die Anteile bleiben 940 - 100 - 40 = 800 Pixel. Es sind 1 + 3 = 4 Anteile, ein Anteil ist also 800 : 4 = 200 Pixel. Die Spalten sind 100, 200 und 600 Pixel breit.

Definition

Formulare und Versand der Eingabedaten

Ein Formular ist ein Element form\texttt{form} mit Eingabefeldern. Das Attribut action\texttt{action} nennt die Adresse, die die Daten verarbeitet, method\texttt{method} die Art des Versands. Eingaben sind input\texttt{input} mit type\texttt{type} (etwa text\texttt{text}, password\texttt{password}, number\texttt{number}, checkbox\texttt{checkbox}, submit\texttt{submit}), select\texttt{select} und textarea\texttt{textarea}. Ein label\texttt{label} beschriftet ein Feld. Das Attribut name\texttt{name} ist der Schlüssel: Beim Absenden schickt der Browser Paare name=wert\texttt{name=wert} an den Server.

Bei GET hängen die Paare an der URL (wie die Anfrage in der URL aus der Mittelstufe). Sie sind sichtbar, stehen im Verlauf und eignen sich für Abfragen ohne Folgen, etwa eine Suche. Bei POST stehen sie im Körper der Anfrage und nicht in der URL. POST nimmt man für Eingaben, die etwas verändern, wie Anmeldung oder Passwort. Sonderzeichen werden prozentkodiert: ein Leerzeichen als +\texttt{+} oder %20\texttt{\%20}, ein ä als %C3%A4\texttt{\%C3\%A4}.

Beispiel

Was sendet der Browser?

ZeileEinrückungAnweisung
10<form action="/anmeldung" method="get">\texttt{<form action="/anmeldung" method="get">}
21<input type="text" name="name">\texttt{<input type="text" name="name">}
31<input type="number" name="kuchen">\texttt{<input type="number" name="kuchen">}
41<button type="submit">Anmelden</button>\texttt{<button type="submit">Anmelden</button>}
50</form>\texttt{</form>}

Lea Maier trägt in das erste Feld ihren Namen und in das zweite die Zahl 2 ein. Was wird gesendet, bei get\texttt{get} und bei post\texttt{post}?

Bei get\texttt{get} ruft der Browser /anmeldung?name=Lea+Maier&kuchen=2\texttt{/anmeldung?name=Lea+Maier\&kuchen=2} auf. Das Fragezeichen leitet die Paare ein, das &\texttt{\&} trennt sie, das Leerzeichen wird zu +\texttt{+}.

Bei post\texttt{post} ruft er /anmeldung\texttt{/anmeldung} auf, und name=Lea+Maier&kuchen=2\texttt{name=Lea+Maier\&kuchen=2} steht im Körper der Anfrage.

Definition

Dynamische Webseiten mit SQL und Benutzerverwaltung

Eine dynamische Webseite wird erst beim Abruf erzeugt. Ein Programm auf dem Server, etwa in Python oder PHP, liest die Formulardaten, fragt per SQL die Datenbank und baut aus dem Ergebnis HTML, das zum Browser zurückgeht. Die Seite zeigt so immer den aktuellen Stand.

Formulardaten stammen von Fremden. Fügt man sie als Text in eine SQL-Anweisung ein, ermöglicht das SQL-Injection. Schutz bieten Platzhalter: Die Anweisung enthält ein ?\texttt{?}, der Wert wird getrennt übergeben und nie als SQL gelesen.

Die Benutzerverwaltung nutzt eine Tabelle, etwa nutzer(id, benutzername, passwort_hash, rolle)\texttt{nutzer(id, benutzername, passwort\_hash, rolle)}. Passwörter speichert man nie im Klartext, sondern als Hashwert mit Salt, einem zufälligen Zusatz je Nutzer, damit gleiche Passwörter verschiedene Hashwerte ergeben. Bei der Anmeldung hasht man das eingegebene Passwort und vergleicht. Danach vergibt der Server eine zufällige Sitzungs-ID, die der Browser als Cookie mitschickt. Authentifizierung prüft, wer jemand ist, Autorisierung, was die Person darf (nur die Rolle orga\texttt{orga} sieht die Anmeldeliste). Die Übertragung läuft über HTTPS.

Beispiel

SQL-Injection und Platzhalter

ZeileEinrückungAnweisung
10abfrage = "SELECT * FROM nutzer WHERE name = ’" + eingabe + "’"\texttt{abfrage = "SELECT * FROM nutzer WHERE name = '" + eingabe + "'"}

Was passiert bei der Eingabe x’ OR ’1’=’1\texttt{x' OR '1'='1}?

Es entsteht SELECT * FROM nutzer WHERE name = ’x’ OR ’1’=’1’\texttt{SELECT * FROM nutzer WHERE name = 'x' OR '1'='1'}. Die Bedingung ’1’=’1’\texttt{'1'='1'} ist immer wahr, die Abfrage liefert alle Nutzer. Mit Platzhalter (WHERE name = ?\texttt{WHERE name = ?}) wird die ganze Eingabe als Name behandelt. Es gibt keinen solchen Nutzer, die Antwort ist leer.

Häufige Fehler

POST verschlüsselt die Daten

„Das Passwort geht per POST, also kann es niemand lesen.“

Richtig ist

POST nimmt die Daten nur aus der URL heraus. Ohne HTTPS laufen sie unverschlüsselt durchs Netz. Die Verschlüsselung leistet HTTPS, nicht POST.

Häufige Fehler

Passwörter im Klartext sind in Ordnung

„Die Datenbank ist geschützt, also kann ich die Passwörter im Klartext speichern.“

Richtig ist

Datenbanken werden gestohlen oder von Mitarbeitenden gelesen. Mit Klartext hätten Angreifer sofort alle Passwörter. Hashwerte mit Salt sind deutlich schwerer zu knacken.

Zusammenfassung

  • HTML5 besteht aus Elementen mit Attributen. Das Grundgerüst hat doctype, html, head und body. Links setzt das Element a mit href.

  • Der Browser baut aus dem HTML den Dokumentbaum, auf den CSS und Skripte zugreifen.

  • CSS-Selektoren wählen nach Typ, Klasse, ID, Lage im Baum und Zustand. Bei Konflikten gewinnt der spezifischere Selektor.

  • Im Grid-Layout ist ein fr ein Anteil des Platzes, der nach festen Größen und Abständen übrig bleibt.

  • Formulare senden Paare name=wert per GET in der URL oder per POST im Körper der Anfrage.

  • Dynamische Seiten fragen die Datenbank per SQL, mit Platzhaltern gegen Injection. Passwörter werden als Hash mit Salt gespeichert.

Übungen

Aufgabe 1Numerisch

Ein body-Element enthält eine Überschrift h1 und eine Liste ul mit drei Einträgen li. Wie viele Elemente hat der Dokumentbaum dieses Ausschnitts, wenn body mitgezählt wird?

Aufgabe 2Multiple Choice

Es gelten die Regeln p { color: navy; }, .hinweis { color: red; } und #kopf { color: green; }. Ein Absatz p hat class="hinweis" und id="kopf". Welche Farbe hat sein Text?

Aufgabe 3Numerisch

Ein Container ist 1000 Pixel breit und hat grid-template-columns: 1fr 2fr sowie gap: 40px. Wie breit ist die zweite Spalte, in Pixeln?

Aufgabe 4Multiple Choice

Welche Aussage zum Absenden eines Anmeldeformulars mit Passwort ist richtig?

Aufgabe 5Freitext

Erkläre, warum ein Platzhalter in einer SQL-Anweisung vor SQL-Injection schützt, und wie ein Passwort in der Benutzertabelle gespeichert werden sollte.