Eingaben prüfen und passend ausgeben: ein PHP-Beispiel
Struktur, Unicode-Längen und fachliche Regeln am Eingang klären und Werte an jeder Ausgabe passend behandeln.

Ein Text kann fachlich gültig sein und an der falschen Ausgabestelle trotzdem gefährlich werden. Ein Link kann korrekt als HTML-Attribut maskiert sein und dennoch auf ein unerwünschtes Protokoll zeigen. Eine syntaktisch richtige Kennung kann zu einem Datensatz gehören, auf den die anfragende Person keinen Zugriff haben darf. Diese Beispiele zeigen, warum Eingabeprüfung, Ausgabe und Berechtigung getrennte Aufgaben sind.
Der folgende Leitfaden entwickelt diese Trennung mit einer kleinen PHP-Textvorschau. Sie nimmt Name, Nachricht und optional eine HTTPS-Adresse entgegen. Sie verschickt nichts und verändert keinen gespeicherten Zustand. Beide Sprachfassungen wurden unter PHP 8.4.27 tatsächlich ausgeführt und im Browser geprüft. Die Beispiele erklären begrenzte Schutzmaßnahmen und sind keine Behauptung, damit sei jede Anwendung insgesamt sicher. Quellenabruf und technische Einordnung: 9. November 2026.
Jede Grenze braucht eine eigene Frage
Am Eingang prüft die Anwendung, ob ein Wert zum vereinbarten Datenmodell passt. Vor einer fachlichen Aktion prüft sie zusätzlich, ob die Aktion erlaubt ist und die betroffenen Daten verwendet werden dürfen. An der Ausgabe sorgt sie dafür, dass ein Wert im vorgesehenen Kontext als Daten behandelt wird. Keine dieser Entscheidungen kann die anderen vollständig ersetzen.
| Aufgabe | Konkrete Frage | Was damit nicht bewiesen ist |
|---|---|---|
| Strukturprüfung | Ist die Nachricht ein einzelner Text und nicht ein verschachteltes Array? | Dass ihr Inhalt fachlich richtig oder zur Veröffentlichung geeignet ist |
| Fachliche Validierung | Liegt ein Enddatum nach dem Startdatum? | Dass der Nutzer den Termin verändern darf |
| Berechtigung | Darf dieses Konto diesen Datensatz bearbeiten? | Dass die spätere HTML-Ausgabe korrekt maskiert ist |
| Kontextgerechte Ausgabe | Bleibt der Text in diesem HTML-Element tatsächlich Text? | Dass eine darin genannte Behauptung wahr ist |
Die OWASP-Anleitung zur Eingabevalidierung unterscheidet entsprechend Struktur, fachliche Regeln und zusätzliche Schutzmaßnahmen. Diese Aufteilung hilft auch beim Debugging: Ein fachlicher Fehler wird nicht durch eine neue Escape-Funktion behoben. Eine unzulässige Aktion wird nicht dadurch erlaubt, dass ihre Parameter schön aussehen.
Den Eingabevertrag vor dem Formular festlegen
Für die Textvorschau werden drei benannte Felder gelesen. Name und Nachricht sind erforderlich. Die Webseite ist optional und muss bei Angabe dem festgelegten HTTPS-Vertrag entsprechen. Jedes Feld erwartet einen einzelnen String. Ein zusätzlich übermitteltes Feld wird nicht in ein beliebiges Anwendungsobjekt übernommen. Insbesondere erzeugt ein eingeschmuggelter Wert mit dem Namen role keine andere Benutzerrolle.
Die fachlichen Längengrenzen betragen im Beispiel 80 Unicode-Codepunkte für den Namen, 1000 für die Nachricht und 2048 für die Adresse. Vor dieser Prüfung gilt zusätzlich eine Grenze von 4096 Bytes je eingelesenem Feld. Das sind bewusst unterschiedliche Größen. Eine Zeichenfolge mit Emojis kann dieselbe Codepunktzahl besitzen wie eine ASCII-Zeichenfolge und trotzdem erheblich mehr Bytes benötigen.
Diese Zahlen sind eine Beispielentscheidung für eine Vorschau und keine universelle Vorgabe für Kontaktformulare. Beschreibe solche Regeln gemeinsam mit dem Produktteam. Wenn die Oberfläche bestimmte Namen oder Nachrichten sinnvoll unterstützen muss, dürfen technische Voreinstellungen diese Anforderungen nicht unbemerkt ausschließen.
Browserprüfungen ersetzen keine Serverprüfung
Die HTML-Eigenschaft required hilft bei der unmittelbaren Rückmeldung im Formular. Sie verhindert nicht, dass ein anderer Client einen abweichenden Request sendet. Genau deshalb wird das Pflichtfeld auf dem Server erneut kontrolliert. Die Fehlerliste des Beispiels entsteht aus den serverseitig geprüften Werten und bleibt auch bei einer direkten Anfrage aussagekräftig.
Eine besonders häufige Abweichung ist ein Array anstelle eines Textes. Ein Request mit name[]=Ada ergibt in PHP eine andere Struktur als name=Ada. Die Anwendung darf diesen Unterschied nicht erst bei der Übergabe an eine Stringfunktion entdecken. Das Beispiel prüft daher den Typ ausdrücklich und verwendet bei einer falschen Struktur keinen scheinbar bereinigten Teilwert weiter.
Dasselbe Prinzip gilt bei JSON-Schnittstellen für fehlende Schlüssel, null, Arrays und verschachtelte Objekte. Ein Schema muss die tatsächlich erlaubten Formen beschreiben. Eine erfolgreiche JSON-Dekodierung beweist nur, dass ein gültiges JSON-Dokument vorliegt. Sie bestätigt weder das erwartete Datenmodell noch eine erlaubte Geschäftsaktion.
Normalisierung ist eine erklärte Produktentscheidung
Die Vorschau vereinheitlicht Zeilenenden und entfernt äußere Leerzeichen. Danach werden verbleibende nicht erlaubte Steuerzeichen geprüft. Nachrichten dürfen Zeilenumbrüche enthalten, der Name soll einzeilig bleiben. Diese Regeln sind offen im Code erkennbar. Sie dürfen nicht als unsichtbare Reparatur alles verändern, was ein Nutzer geschrieben hat.
Der Code zählt Unicode-Codepunkte, keine vom Menschen wahrgenommenen Schriftzeichen. Ein Buchstabe mit einem gesonderten kombinierenden Akzent kann mehrere Codepunkte enthalten. Für einen Zähler in der Oberfläche und seine Fehlermeldung muss diese Unterscheidung verstanden werden. Wer stattdessen Graphemgruppen begrenzen möchte, braucht dafür eine passende gemeinsame Regel und ein geeignetes Werkzeug.
Eine automatische Normalisierung auf eine bestimmte Unicode-Form ist im Beispiel nicht enthalten. Bei Identifikatoren kann sie für konsistente Vergleiche wichtig sein, muss aber vor Validierung und Speicherung bewusst definiert werden. Bei freiem Text darf sie nicht unbemerkt als vermeintliche Sicherheitsbereinigung eingeführt werden.
Nicht nach einer Liste böser Wörter suchen
Das Beispiel entfernt keine Apostrophe und verbietet nicht pauschal jedes Winkelzeichen. Ein Wert mit solchen Zeichen bleibt Text. Seine sichere Darstellung entsteht an der Ausgabe. Ein Verbot einzelner Zeichen würde legitime Inhalte beschädigen und zugleich keine vollständige XSS-Abwehr ergeben. Bei einem Namen mit Apostroph wäre der sichtbare Schaden sofort erkennbar.
Eine Zulassungsregel beschreibt stattdessen, welche Form die Anwendung benötigt: einen einzelnen UTF-8-Text, eine bestimmte Länge und gegebenenfalls eine erlaubte Auswahl. Ein festes Auswahlfeld kann exakt auf seine erlaubten Werte geprüft werden. Freie Nachrichten benötigen eine andere Regel als eine Artikelnummer oder ein Kalenderdatum. Eine einzige globale Bereinigungsfunktion kann diese Unterschiede nicht sinnvoll abbilden.
Für die Vorschau ist die Nachricht ausdrücklich reiner Text. Wenn ein anderes Produkt tatsächlich formatiertes HTML akzeptieren soll, liegt ein anderer Vertrag vor. Dann braucht es eine gepflegte, auf erlaubte HTML-Strukturen abgestimmte Sanitizing-Lösung. Eine selbst geschriebene Liste zu entfernender Tags oder ein regulärer Ausdruck ist dafür kein gleichwertiger Ersatz.
HTML-Text und zitierte Attribute gezielt maskieren
Die Hilfsfunktion html verwendet htmlspecialchars mit ausdrücklich gesetzten Optionen und UTF-8. Sie wird dort eingesetzt, wo Werte in HTML-Text oder in vollständig zitierte, vorgesehene Attribute gelangen. Die PHP-Dokumentation zu htmlspecialchars beschreibt die umgewandelten Zeichen und das Verhalten bei ungültigen Kodierungsfolgen.
Ein Name wie <b>Text</b> erscheint dadurch als Zeichenfolge statt als neues HTML-Element. In einem value-Attribut darf ein übermitteltes Anführungszeichen nicht das Attribut beenden. Der Browser soll weiterhin einen einzigen Eingabewert lesen. Das funktioniert nur zusammen mit einer kontrollierten HTML-Struktur und fest benannten Attributen.
Die Funktion ist keine allgemeine Freigabe für jede Stelle einer Webseite. Ein Ereignisattribut, ein JavaScript-Ausdruck und eine dynamische CSS-Deklaration haben andere Regeln. Für solche Stellen ist es häufig sinnvoller, die Konstruktion zu vermeiden und Daten über einen klar begrenzten Weg zu übergeben.

Eine vollständige PHP-Textvorschau
Die folgende Datei lässt sich als eigenständige Lernseite ausführen. Sie enthält die Eingabeprüfung, das Formular und die bedingte Vorschau. Die Funktion textField bekommt nur die benötigten Parameter. Ihre Fehler werden in einem eigenen Array gesammelt. Ein zu großer oder ungültig kodierter Wert wird nicht erneut vollständig ausgegeben.
<?php
declare(strict_types=1);
header('Content-Type: text/html; charset=UTF-8');
header('Cache-Control: no-store');
header('X-Content-Type-Options: nosniff');
function html(string $value): string {
return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
function textField(array $input, string $key, int $maxChars,
bool $required, bool $multiline, array &$errors): string {
$value = $input[$key] ?? '';
if (!is_string($value)) {
$errors[$key] = 'Bitte einen einzelnen Textwert eingeben.';
return '';
}
if (strlen($value) > 4096 || preg_match('//u', $value) !== 1) {
$errors[$key] = 'Der Wert ist zu lang oder nicht gültig kodiert.';
return '';
}
$value = str_replace(["\r\n", "\r"], "\n", $value);
$value = trim($value);
$controls = $multiline ? '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/'
: '/[\x00-\x1F\x7F]/';
if (preg_match($controls, $value) === 1 ||
preg_match_all('/./us', $value) > $maxChars ||
($required && $value === '')) {
$errors[$key] = 'Bitte einen Text in der vorgesehenen Länge eingeben.';
}
return $value;
}
$errors = [];
$values = ['name' => '', 'message' => '', 'website' => ''];
$submitted = ($_SERVER['REQUEST_METHOD'] ?? '') === 'POST';
if ($submitted) {
$values['name'] = textField($_POST, 'name', 80, true, false, $errors);
$values['message'] = textField($_POST, 'message', 1000, true, true, $errors);
$values['website'] = textField($_POST, 'website', 2048, false, false, $errors);
if ($values['website'] !== '' && !isset($errors['website'])) {
$parts = parse_url($values['website']);
if (filter_var($values['website'], FILTER_VALIDATE_URL) === false ||
!is_array($parts) || strtolower($parts['scheme'] ?? '') !== 'https' ||
empty($parts['host']) || isset($parts['user']) || isset($parts['pass'])) {
$errors['website'] = 'Bitte eine HTTPS-Adresse ohne Zugangsdaten eingeben.';
}
}
}
$ready = $submitted && $errors === [];
$json = $ready ? json_encode($values,
JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_THROW_ON_ERROR) : null;
?>
<!doctype html><html lang="de"><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Textvorschau</title>
<style>body{font:1rem/1.5 system-ui;margin:1rem auto;padding:0 1rem;max-width:42rem}label{display:block;margin-top:1rem}input,textarea,button{font:inherit;box-sizing:border-box;max-width:100%}input,textarea{width:100%;padding:.6rem}button{padding:.6rem 1rem;margin-top:1rem}#preview-message{white-space:pre-wrap;overflow-wrap:anywhere}#preview-name,a{overflow-wrap:anywhere}:focus-visible{outline:3px solid #be2028;outline-offset:3px}</style>
<h1>Textvorschau erstellen</h1>
<?php if ($errors): ?><section aria-labelledby="errors-title"><h2 id="errors-title">Bitte Eingaben prüfen</h2><ul>
<?php foreach ($errors as $field => $error): ?>
<li><a href="#<?= html($field) ?>"><?= html($error) ?></a></li>
<?php endforeach; ?></ul></section><?php endif; ?>
<form method="post" action="">
<label for="name">Name</label>
<input id="name" name="name" value="<?= html($values['name']) ?>" required>
<label for="message">Nachricht</label>
<textarea id="message" name="message" rows="5" required><?= html($values['message']) ?></textarea>
<label for="website">Webseite als HTTPS-Adresse, optional</label>
<input id="website" name="website" value="<?= html($values['website']) ?>">
<button>Vorschau erstellen</button>
</form>
<?php if ($ready): ?><section id="preview" aria-labelledby="preview-title">
<h2 id="preview-title">Ihre Textvorschau</h2>
<h3 id="preview-name"><?= html($values['name']) ?></h3>
<p id="preview-message"><?= html($values['message']) ?></p>
<?php if ($values['website'] !== ''): ?>
<a id="preview-link" href="<?= html($values['website']) ?>" rel="noreferrer noopener"><?= html($values['website']) ?></a>
<?php endif; ?></section>
<script id="preview-data" type="application/json"><?= $json ?></script>
<?php endif; ?></html>
Die Ausgabe erfolgt erst, wenn die Prüfung der vorgesehenen Felder abgeschlossen ist. Bei Fehlern bleibt das Formular mit einer verlinkten Fehlerübersicht sichtbar. Ein gültiger Wert wird nicht deshalb als versendete Nachricht bezeichnet. Die Anwendung erstellt lediglich die angekündigte Textvorschau. Diese klare Funktionsgrenze verhindert eine Erfolgsmeldung für eine Aktion, die gar nicht stattfindet.
Die Seite verändert keinen gespeicherten Zustand. Sie ist damit kein vollständiges Kontaktformular mit Versand, kein Benutzerkonto und kein Veröffentlichungsdienst. Entsprechende zusätzliche Funktionen würden eigene Anforderungen an Berechtigungen, Missbrauchsschutz, Fehlerbehandlung und gegebenenfalls den Schutz zustandsändernder Anfragen hinzufügen.
Eine HTTPS-Adresse braucht mehr als HTML-Maskierung
Die optionale Adresse wird zunächst als einzelner Text geprüft. Anschließend kontrolliert das Beispiel die URL-Struktur, das ausdrücklich erlaubte Schema https und das Vorhandensein eines Hosts. Eingebettete Zugangsdaten werden abgelehnt. Erst nach diesen Prüfungen wird der Wert für das zitierte href-Attribut maskiert.
Die Dokumentation zu filter_var ist hier besonders wichtig: Der voreingestellte Standardfilter führt keine allgemeine Validierung aus. Das Beispiel benennt FILTER_VALIDATE_URL ausdrücklich. Auch dieser Filter ersetzt die zusätzliche Produktregel zum erlaubten Schema und zu Zugangsdaten nicht.
Eine strukturell zulässige HTTPS-Adresse ist kein Vertrauensbeweis für die Zielseite. Sie kann weiterhin irreführende Inhalte anbieten. Die Vorschau ruft diese Adresse serverseitig nicht ab. Sollte eine Anwendung später Vorschaudaten von fremden Adressen laden, entsteht ein zusätzlicher Prüfbereich, etwa hinsichtlich unerwünschter Serverzugriffe. Die Linkprüfung des Beispiels darf dann nicht unverändert als vollständige Absicherung dieses neuen Dienstes ausgegeben werden.
JSON für die konkrete Einbettung erzeugen
Die gültigen Vorschauwerte werden zusätzlich als JSON-Daten in einem script-Element mit dem Typ application/json bereitgestellt. Sie sind dort keine ausführbare JavaScript-Anweisung. Trotzdem darf ein übermittelter Text nicht die umgebende HTML-Struktur beenden. Die verwendeten JSON_HEX-Optionen verhindern entsprechende Klartextzeichen in dieser Einbettung.
Die PHP-Dokumentation zu json_encode erläutert diese Optionen und die Fehlerbehandlung. JSON_THROW_ON_ERROR macht einen Kodierungsfehler erkennbar. Eine nachträgliche Anwendung von htmlspecialchars auf diesen JSON-Inhalt wäre keine passende Ersatzlösung: Das script-Datenfeld ist kein gewöhnlicher HTML-Textknoten für diese Art der Interpretation.
Für eine eigenständige JSON-Antwort wäre wiederum der passende Antworttyp und ein eigener Schnittstellenvertrag erforderlich. Der Code zeigt ausdrücklich eine Einbettung in eine HTML-Seite. Er soll keine einzige universelle JSON-Funktion für jede denkbare Übertragungssituation versprechen.
Auch der weitere DOM-Weg muss Text bleiben
Wenn JavaScript die JSON-Daten später liest, darf die geprüfte Zeichenfolge nicht plötzlich als HTML interpretiert werden. Eine Ausgabe über textContent bewahrt den reinen Textvertrag. Eine Übergabe an innerHTML würde dagegen einen neuen Interpretationsschritt eröffnen. Die frühere serverseitige Maskierung einer anderen Ausgabestelle schützt diesen neuen Schritt nicht automatisch.
Die OWASP-Anleitung zur XSS-Abwehr beschreibt diese kontextbezogene Betrachtung und geeignete Ausgabestellen. Ein sauberer Datenfluss benennt daher Quelle, Verarbeitung und Ziel. „Der Wert war schon einmal bereinigt“ ist keine ausreichende Beschreibung des letzten Schritts.
Die gleiche Aufmerksamkeit ist bei Komponentenbibliotheken erforderlich. Wenn eine Hilfsfunktion einen Text später in HTML umwandelt, verändert sie den Vertrag. Prüfe ihre tatsächliche Verwendung statt nur den Typnamen einer übergebenen Variablen. Für gewollte HTML-Inhalte sind eine passende Bereinigung und ihre Grenzen gesondert zu dokumentieren.
Was die tatsächlichen Prüfungen zeigen
Die beiden PHP-Dateien wurden zunächst auf Syntax geprüft und danach über einen echten PHP-Testserver aufgerufen. Für jede Sprache wurden 24 unterschiedliche Anfragen verarbeitet. Dazu gehörten normale Unicode-Namen, die Zeichenfolge 0, fehlende Pflichtwerte, Arrays anstelle von Strings, ungültiges UTF-8 und die vereinbarten Längengrenzen.
Weitere Fälle enthielten HTML-ähnlichen Text, Anführungszeichen, einen schließenden textarea-Text und einen schließenden script-Text. Die Rückgaben wurden im Browser interpretiert. Dabei wurde kontrolliert, dass Vorschau und JSON die vorgesehenen Textwerte bewahren und keine eingeschmuggelten Elemente oder Ereignisattribute entstehen. Die Vorschau enthielt keine Content-Security-Policy, die eine fehlerhafte Ausgabe im Test verdeckt hätte.
Zusätzlich wurden beide Formulare tatsächlich im Browser ausgefüllt und per POST abgesendet. In der schmalen Ansicht wurde auf horizontalen Überlauf geprüft. Insgesamt bestanden 242 Prüfbedingungen, 48 serverseitig verarbeitete Fälle und zwei zusätzliche Browser-Formularabläufe. Diese Zahlen beschreiben genau den ausgeführten Versuch und keine allgemeine Zertifizierung der Anwendung.
Fehler verständlich und ohne Datenverlust behandeln
Ein gültig eingelesener Wert bleibt bei einem fachlichen Fehler im Formular sichtbar. Die Maskierung erfolgt bei seiner Darstellung. Der Nutzer muss deshalb nicht alle anderen Felder neu schreiben, nur weil die optionale Adresse nicht dem vereinbarten Vertrag entspricht. Ein strukturell falscher oder übermäßig großer Wert wird dagegen nicht blind als riesiger Formularinhalt zurückgespiegelt.
Die Fehlerübersicht verlinkt auf die betroffenen Felder. Ihre Texte stammen aus einer kontrollierten Liste. Die Anwendung fügt nicht den vollständigen fehlerhaften Request in die Fehlermeldung ein. Das hilft sowohl der Lesbarkeit als auch dem Umgang mit unerwünschten Inhalten. Bei komplexeren Formularen kommen feldbezogene Zuordnungen und eine abgestimmte Fokusführung hinzu.
Beschreibe außerdem die tatsächlich geltenden Regeln. Ein Formularzähler für wahrgenommene Schriftzeichen würde nicht exakt zur hier verwendeten Codepunktgrenze passen. Eine verständliche Benutzeroberfläche und eine strenge Serverregel sollten dieselbe Produktentscheidung erklären, statt sich gegenseitig zu widersprechen.
Grenzen des kleinen Beispiels ernst nehmen
Die Feldgrenze von 4096 Bytes wird erst nach dem Einlesen durch PHP geprüft. Sie begrenzt nicht bereits den Netzwerkrequest oder den vorgelagerten Parser. Für einen öffentlich betriebenen Dienst sind geeignete Grenzen vor und während der Verarbeitung erforderlich. Das kleine Beispiel behauptet keinen Schutz gegen beliebig große Anfragen oder jede Form von Ressourcenmissbrauch.
Eine spätere Datenbankspeicherung braucht parametrisierte Abfragen und eine passende Datenmodellprüfung. HTML-Maskierung ist kein SQL-Schutz. Eine zustandsändernde Funktion braucht eine Prüfung der erlaubten Aktion und gegebenenfalls weitere Maßnahmen gegen unerwünschte Anfragen. Eine gültige Kennung bedeutet nicht, dass das anfragende Konto den zugehörigen Datensatz verwenden darf.
Auch Protokolle sind Ausgaben. Wenn ein System fremde Daten in eine Verwaltungsseite oder ein Analysewerkzeug übernimmt, muss dort der passende Kontext berücksichtigt werden. Begrenze außerdem, welche Inhalte überhaupt protokolliert werden. Eine sichere öffentliche Vorschau rechtfertigt keinen unkontrollierten vollständigen Mitschnitt aller Nachrichten.
Rohdaten und Darstellung nicht verwechseln
Speichere fachlich geeignete Textwerte nicht allein als bereits für eine bestimmte HTML-Ausgabe maskierte Zeichenfolgen. Ein späterer Export, eine API oder eine andere Oberfläche benötigt möglicherweise eine andere Darstellung. Wenn Maskierung und eigentliche Daten vermischt werden, entstehen leicht doppelt sichtbare Entitäten oder eine spätere unsichere Rückwandlung.
Lege die erlaubte Normalisierung am Eingang fest und maskiere am jeweiligen Ausgabepunkt. So kann derselbe fachliche Wert einmal als HTML-Text, einmal als JSON-Datum und einmal in einem Dokument erscheinen. Jede Ausgabe folgt ihrer eigenen Regel. Das ist nachvollziehbarer als ein globales Feld mit der unpräzisen Bezeichnung „sicherer Inhalt“.
Überprüfe solche Entscheidungen bei Schnittstellenwechseln. Eine bisher interne Notiz kann später öffentlich erscheinen. Ein schlichtes Textfeld kann durch einen Editor zu formatiertem Inhalt werden. Beide Änderungen verändern den Datenvertrag und benötigen eine neue Betrachtung der Verarbeitung und Ausgabe.
Die Ausgabeentscheidung im Review sichtbar machen
| Ziel im Beispiel oder späteren Ausbau | Benötigte Entscheidung |
|---|---|
| Name als Überschrift | HTML-Text maskieren und den Elementnamen fest vorgeben |
| Name im Eingabefeld | Attributwert maskieren und vollständig in Anführungszeichen setzen |
| Webseitenadresse als Link | Zuerst die URL-Regel prüfen, danach das vorgesehene href-Attribut maskieren |
| Daten im JSON-Scriptblock | JSON passend zur HTML-Einbettung erzeugen und Fehler behandeln |
| Spätere JavaScript-Anzeige | Den vereinbarten Text über textContent statt HTML-Interpretation ausgeben |
| Spätere Datenbankabfrage | Werte über eine geeignete parametrisierte Abfrage übergeben und Zugriffsrechte prüfen |
Diese Übersicht kann als konkrete Gesprächsgrundlage neben dem Code stehen. Eine prüfende Person benennt für jede Ausgabestelle das Ziel und kontrolliert anschließend genau die dort verwendete Funktion. Bei einer späteren Änderung wird die Zeile erneut betrachtet. Wird aus einer Textüberschrift beispielsweise ein Link, ist nicht nur die HTML-Struktur anders: Es kommt eine Entscheidung über das erlaubte Ziel hinzu. Ein unveränderter Aufruf derselben bisherigen Hilfsfunktion wäre dafür keine ausreichende Begründung.
Checkliste für die Codeprüfung
- Typ, erforderliche Felder, erlaubte Werte und Längen sind pro Feld definiert.
- Arrays, fehlende Werte und ungültige Kodierung werden bewusst behandelt.
- Die Bedeutung von Bytes, Codepunkten und sichtbaren Schriftzeichen ist geklärt.
- Normalisierung und fachliche Validierung sind als getrennte Schritte verständlich.
- Die Anwendung übernimmt nur die vorgesehenen Felder in ihre Verarbeitung.
- HTML-Text und zitierte Attribute werden am tatsächlichen Ausgabepunkt maskiert.
- URL-Schemata und andere fachliche URL-Regeln werden zusätzlich kontrolliert.
- JSON wird für seinen konkreten Übertragungs- oder Einbettungskontext erzeugt.
- Spätere DOM-Ausgaben bewahren den vereinbarten Textvertrag.
- Berechtigungen, Datenbankzugriffe und zustandsändernde Aktionen werden gesondert geprüft.
- Grenzfälle und erlaubte ungewöhnliche Eingaben sind tatsächlich ausprobiert.
- Die Dokumentation verspricht nur die Schutzwirkung, die der Code tatsächlich liefert.
Mit einem vollständigen Datenweg anfangen
Wähle für eine erste Überarbeitung ein Feld und verfolge seinen gesamten Weg: Request, Parsing, Normalisierung, fachliche Prüfung, mögliche Speicherung und jede Ausgabe. Notiere an jeder Grenze, welcher Vertrag gilt. Diese konkrete Betrachtung findet Fehler, die bei der isolierten Suche nach einer fehlenden Escape-Funktion leicht verborgen bleiben.
Erweitere anschließend die Tests um echte Grenzfälle der Anwendung. Erlaubte Namen mit Apostrophen sind ebenso wichtig wie abgewiesene gefährliche URL-Schemata. Gute Eingabeprüfung schützt die fachliche Funktion und respektiert zulässige Daten. Gute Ausgabe sorgt dafür, dass diese Daten im vorgesehenen Kontext bleiben. Zusammen entsteht ein überprüfbarer Ablauf, dessen Grenzen klar benannt werden können.








