Wo Webentwickler das erste Mal SQL schreiben, passiert es: Sie bauen eine Abfrage aus Nutzereingaben zusammen. Injection steht in den OWASP Top 10 von 2021 auf Platz 3; Platz 1 ist Broken Access Control. Wer die Lücke nicht kennt, öffnet jedem Angreifer die Tür zur Datenbank.
Injection heißt: Eingabedaten werden vom Programm als Befehl gelesen, weil Befehl und Daten im selben Textfluss stehen. SQL ist die Abfragesprache relationaler Datenbanken, mit Befehlen wie SELECT, INSERT, UPDATE und DELETE. Vermischt eine Abfrage SQL-Text und Nutzereingabe, kann die Datenbank sie nicht mehr unterscheiden.
Ein Login-Formular zeigt es. Der Code hängt den Benutzernamen per String-Verkettung an einen SELECT-String an. Die Eingabe mit einem Hochkomma und einem immer wahren Vergleich beendet den Originaltext und fügt einen eigenen SQL-Befehl hinzu. Die Passwortprüfung fällt, weil die Bedingung für jede Zeile wahr ist.
Die wirksamste Abwehr sind parametrisierte Abfragen, auch Prepared Statements genannt. Der SQL-Text enthält nur Fragezeichen als Ersatz für die Werte. Diese Werte werden getrennt vom SQL-Text übertragen, deshalb liest die Datenbank sie nie als Teil des Befehls. String-Verkettung ist nie sicher, auch nicht mit Filtern.
Verwechselt wird Injection oft mit Validierungsfehlern. Validierung prüft, ob Daten erlaubt sind. Separation sorgt dafür, dass Daten überhaupt nicht als Befehl gelesen werden können.
Injection ist nicht ein Problem falscher Daten, sondern der Vermischung von Befehl und Daten. Getrennt übertragene Werte scheiden beides – und dokumentieren nebenbei, welche Eingaben Daten sind.
📌 SQL-Injection · String-Verkettung · Prepared Statements
📚 Webentwicklung von Grund auf · Tag 6 von 30
#WebSecurity #webdev #NodeJS
Viele denken, ein Test müsse „echt“ sein, also mit echter Datenbank und echten APIs, sonst sei er wertlos. Das klingt plausibel, weil Software am Ende ja wirklich laufen muss.
Tatsächlich prüft ein Unit-Test nur eine Einheit isoliert – meist eine einzelne Funktion oder Methode einer Klasse. Abhängigkeiten wie Datenbanken oder APIs werden dafür durch Test-Doubles ersetzt, also Nachahmungen, die festgelegte Werte liefern. Solche Tests laufen in Millisekunden und ganz ohne Netz. Das Zusammenspiel mit echten Nachbarn prüfen stattdessen Integrationstests, etwa gegen eine echte PostgreSQL-Instanz.
Der Irrtum entsteht, weil „Test“ sich erst einmal gleich anhört, egal welche Schicht er prüft. Die Testpyramide rät deshalb ausdrücklich: viele schnelle Unit-Tests, weniger Integrationstests und wenige End-to-End-Tests, also Tests über die gesamte Anwendung hinweg.
Ein Beispiel: Eine Funktion berechnet den Bruttopreis aus Nettopreis und Steuersatz. Ihr Unit-Test ruft sie mit konkreten Werten auf und vergleicht das Ergebnis mit dem erwarteten Wert, ganz ohne Datenbank. In Node.js reicht dafür seit Version 20 der eingebaute Test-Runner node:test.
„Woran man es erkennt:“ Läuft der Test offline in Millisekunden, prüft er eine Einheit. Berührt er Datenbank oder Netzwerk, ist er ein Integrationstest – und gegen eine gemockte Datenbank findet er keine SQL-Fehler, denn dafür gehört mindestens ein Test gegen die echte Datenbank-Engine dazu.
Unit heißt nicht „kleiner Test von irgendetwas“, sondern isolierte Prüfung einer Einheit mit Test-Doubles für alle Abhängigkeiten.
📌 Einheit isoliert · Test-Doubles · Testpyramide
📚 Webentwicklung von Grund auf · Tag 6 von 30
#testing #NodeJS #typescript #webdev
Ein Bauherr plant ein Haus und notiert: sechs Ziegelsteine, eine Tür, vier Wasserhähne. Er legt keine echten Ziegel auf den Tisch, nur die Liste. Der Lieferdienst liest sie und liefert passende Teile ans Grundstück. Das fertige Lager auf dem Grundstück entsteht aus der Liste.
Node.js ist die Laufzeitumgebung, die JavaScript außerhalb des Browsers ausführt. Die Liste ist package.json, das zentrale Dokument jedes Node-Projekts. npm, der Paketmanager von Node.js, liest diese Datei und lädt aus dem zentralen Paketarchiv, der Registry, die nötigen Bausteine herunter. Sie landen im Ordner node_modules, der alle installierten Pakete samt deren eigenen Abhängigkeiten enthält.
Eine Abhängigkeit (Dependency) ist ein fremdes Programmpaket, das der eigene Code zum Laufen braucht, etwa Express für HTTP-Anfragen. In package.json steht unter dependencies der Eintrag "express": "^4.18.0". Das Caret vor der Zahl erlaubt jede 4er-Version ab 4.18.0; die drei Ziffern 1.2.3 bedeuten major.minor.patch – brechende Änderung, neue Funktion, Fehlerbehebung.
Das Bild hat eine Grenze: Eine Einkaufsliste nennt Zutaten meist exakt, "^4.18.0" ist ein erlaubter Bereich. Ohne die Sperrdatei package-lock.json kann npm auf einem Rechner 1.2.3 wählen, auf einem anderen 1.9.0. Die Sperrdatei friert die tatsächlich gewählten Versionen ein.
Deshalb gilt: package.json und package-lock.json gehören in die Versionsverwaltung (Git), node_modules nicht. Die Liste reicht, um überall dieselben Bausteine neu zu bestellen.
📌 Abhängigkeit · Versionsbereich · Sperrdatei
📚 Webentwicklung von Grund auf · Tag 4 von 30
#NodeJS #javascript #webdev
Verantwortlich dafür ist die Event-Loop, eine laufende Schleife im Hauptthread. Sie prüft, ob abgeschlossene Hintergrundvorgänge Ergebnisse geliefert haben, und ruft dann die zugehörigen Funktionen auf.
🌐 Eine gestartete Lese- oder Netzwerkoperation gibt den Hauptthread sofort frei. Das nennt man asynchron: Das Programm wartet nicht, sondern arbeitet weiter und kommt später zurück, wenn das Ergebnis bereitliegt. Ein Callback ist eine Funktion, die als Argument mitgegeben und beim Eintritt des Ereignisses aufgerufen wird. Bei await verbirgt der Compiler genau dieses Muster hinter einer scheinbar linearen Schreibweise.
🧩 „Asynchron“ heißt nicht „parallel“. Es gibt nur einen Hauptthread, der nacheinander arbeitet. Liest ein Server eine Datei mit fs.readFile, kann er währenddessen weitere HTTP-Anfragen annehmen; mit fs.readFileSync stehen alle anderen Anfragen still. Der Fortschritt entsteht durch Weiterarbeiten während des Wartens, nicht durch gleichzeitige Ausführung.
🔒 Eine blockierte Event-Loop ist kein Leistungsproblem, sondern ein Stillstand. Auch JSON.parse und JSON.stringify sind synchron; sehr große Dokumente halten die Schleife für die Dauer der Verarbeitung an. Dann steht jede Anfrage still, weil schlicht nichts mehr ausgeführt wird. Node.js empfiehlt daher, CPU-intensive Arbeit in Worker Threads auszulagern, eigene Threads mit eigenem Event-Loop und Nachrichtenaustausch.
Asynchron heißt nicht „schneller rechnen“, sondern „weiterarbeiten, während gewartet wird“.
📌 Event-Loop · Asynchron · Hauptthread
📚 Webentwicklung von Grund auf · Tag 4 von 30
#NodeJS #javascript #webdev
Die Annahme klingt plausibel: JavaScript entstand für Webseiten, und dort sieht man es auch. Wer Buttons, Formulare und Animationen kennt, verbindet die Sprache fest mit Browser und Frontend.
Tatsächlich ist der Browser nur eine Laufzeitumgebung – also das Programm, das die Sprache überhaupt ausführen kann. Es enthält die Sprach-Engine und Bibliotheken, über die der Code sein Betriebssystem erreicht. Die Sprache selbst definiert die ECMAScript-Norm, und jede Umgebung legt fest, was sie darf. Node.js ist eine solche Umgebung und führt JavaScript außerhalb des Browsers aus, etwa auf einem Server. Sie ergänzt die Sprache um Module für Dateizugriffe und um eines, das einen HTTP-Server startet, der Anfragen entgegennimmt und antwortet.
Der Irrtum entsteht, weil Einsteiger JavaScript fast ausschließlich im Frontend erleben. Dort laufen die Sprache und der Browser scheinbar immer gemeinsam auf.
Ein kleines Skript zeigt den Unterschied: Unter Node.js liest es eine Datei ein und zählt Wörter. Genau dieses JavaScript hat vorher vielleicht einen Button im Browser verarbeitet. Wird daraus ein Server, beantwortet er etwa die Anfrage GET /artikel/42 mit einem Datensatz im JSON-Format.
Woran man es erkennt: Läuft Code ohne geöffnetes Browserfenster, ist er nicht im Frontend, sondern im Backend unterwegs. Frontend und Backend sind keine Ordner, sondern Lauforte derselben Sprache.
JavaScript heißt nicht „die Browsersprache“, sondern eine Sprache mit wechselnden Lauforten. Wer Werkzeuge wie npm nutzt, fährt bereits Node.js, ohne es zu bemerken.
📌 Laufzeitumgebung · Node.js · Frontend und Backend als Lauforte
📚 Webentwicklung von Grund auf · Tag 4 von 30
#javascript #NodeJS #webdev
Stellen Sie sich die Poststelle einer Behörde vor. Der Sachbearbeiter prüft den Antrag und stempelt ihn: grüner Stempel bedeutet erledigt, ein gelber bedeutet „woanders vorstellig werden“, ein roter mit Ihrer Nummer bedeutet Fehler im Antrag, ein roter mit seiner Nummer bedeutet Störung im Amt. Wer den Stempel sieht, weiß sofort, wo die Suche beginnt. Die Nummer auf dem Stempel nennt das genaue Büro. Der Farbcode aber nennt die Richtung.
So arbeitet HTTP, das Protokoll (Regelwerk) des Webs. Jede Serverantwort beginnt mit einem Statuscode, einer dreistelligen Nummer, die das Ergebnis der Anfrage ausdrückt. Die erste Ziffer bestimmt die Klasse: 2xx Erfolg, 3xx Umleitung an eine andere Adresse, 4xx Fehler in der Anfrage des Clients, 5xx Problem auf dem Server. Der Rumpf der Nummer unterscheidet dann innerhalb der Klasse.
Typisches Beispiel: Eine Anfrage liefert 404 Not Found, also Klasse 4xx. Dann zuerst die eigene Anfrage prüfen: URL, mitgesendete Daten, Anmeldung. Liefert sie stattdessen 500, liegt der unerwartete Serverfehler auf der Gegenseite; die Anfrage kann oft später unverändert erneut gesendet werden.
Das Bild hat eine Grenze: Der Stempel der Post nennt meist die genaue Ursache, ein Statuscode nur die Richtung. Zwei 4xx-Antworten können völlig verschiedene Probleme bedeuten. Die Nummer ist ein Wegweiser, keine Diagnose.
4xx heißt nicht „Server kaputt“, sondern „Anfrage prüfen“ – 5xx zeigt auf die Gegenseite.
📌 Erste Ziffer · 4xx Client · 5xx Server
📚 Webentwicklung von Grund auf · Tag 2 von 30
#HTTP #webdev #api #NodeJS