Java Web Aufbau – Tag 3 von 10
Von Elyndra Valen, Senior Developer bei Java Fleet Systems Consulting

🗺️ Deine Position im Kurs
| Tag | Thema | Status |
|---|---|---|
| 1 | Filter im Webcontainer | ✅ Abgeschlossen |
| 2 | Listener im Webcontainer | ✅ Abgeschlossen |
| → 3 | Authentifizierung gegenüber einer Datenbank | 👉 DU BIST HIER! |
| 4 | Container-Managed Security & Jakarta EE Security API | 🔒 Noch nicht freigeschaltet |
| 5 | Custom Tags & Tag Handler (SimpleTag) | 🔒 Noch nicht freigeschaltet |
| 6 | Custom Tag Handler mit BodyTagSupport | 🔒 Noch nicht freigeschaltet |
| 7 | JPA vs JDBC – Konfiguration & Persistence Provider | 🔒 Noch nicht freigeschaltet |
| 8 | Relationen (1) in der JPA – @OneToOne & @ManyToOne | 🔒 Noch nicht freigeschaltet |
| 9 | Relationen (2) in der JPA – @OneToMany & @ManyToMany | 🔒 Noch nicht freigeschaltet |
| 10 | JSF Überblick – JavaServer Faces | 🔒 Noch nicht freigeschaltet |
Modul: Java Web Aufbau
Gesamt-Dauer: 10 Arbeitstage (je 8 Stunden)
Dauer heute: 8 Stunden
Dein Ziel: Ein production-ready Login-System mit Datenbank-basierter Authentifizierung implementieren
📦 Projekt-Übersicht
Dieses Maven-Projekt demonstriert ein production-ready Login-System mit:
- ✅ Passwort-Hashing mit SHA-256
- ✅ SQL-Injection-Schutz mit Prepared Statements
- ✅ Session-basierter Authentifizierung
- ✅ JDBC Connection-Handling
🗂️ Projekt-Struktur
AuthDemo-Tag03/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── ibb/ │ │ │ ├── ctrl/ # Servlets │ │ │ │ └── SigninServlet.java │ │ │ ├── model/ # Domain-Modelle │ │ │ │ └── Customer.java │ │ │ └── util/ # Helper-Klassen │ │ │ └── GConnection.java │ │ ├── resources/ # Konfigurationsdateien │ │ └── webapp/ # Web-Ressourcen │ │ ├── WEB-INF/ │ │ │ └── web.xml │ │ ├── signin.jsp # Login-Formular │ │ ├── index.jsp # Dashboard │ │ └── signout.jsp # Logout │ └── test/ # JUnit Tests ├── pom.xml # Maven Dependencies └── README.md # Diese Datei
🔧 Voraussetzungen
Software:
- ✅ Java JDK 17 oder höher
- ✅ Maven 3.6 oder höher
- ✅ Payara Server 6.x oder Tomcat 10.x
- ✅ MySQL 8.0 oder höher
- ✅ NetBeans IDE (empfohlen) oder IntelliJ IDEA
🗄️ Datenbank-Setup
1. Datenbank erstellen
CREATE DATABASE shopdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE shopdb;
2. Tabelle erstellen
CREATE TABLE customer (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(64) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
3. Test-User anlegen
-- Passwort: test123
INSERT INTO customer (email, password)
VALUES ('test@example.com', 'ecd71870d1963316a97e3ac3408c9835ad8cf0f3c1bc703527c30265534f75ae');
Hinweis: Der Hash ecd71...75ae entspricht dem Passwort „test123“ mit SHA-256.
🚀 Installation & Start
Option 1: Mit NetBeans IDE
- Projekt öffnen:
- File → Open Project
Onlineshop-Tag03-Aufbauauswählen
- Dependencies laden:
- Rechtsklick auf Projekt → Clean and Build
- Maven lädt automatisch alle Dependencies
- Server konfigurieren:
- Rechtsklick auf Projekt → Properties → Run
- Server: Payara Server auswählen
- Context Path:
/AuthDemo
- Datenbank-Verbindung anpassen:
GConnection.javaöffnen- DB-Credentials anpassen:
private static final String DB_URL = "jdbc:mysql://localhost:3306/shopdb"; private static final String DB_USER = "root"; private static final String DB_PASSWORD = "root"; - Projekt deployen:
- F6 drücken oder Run → Run Project
- App öffnen:
- Browser:
http://localhost:8080/AuthDemo/signin.jsp
- Browser:
Option 2: Mit Maven CLI
# Dependencies installieren mvn clean install # WAR-Datei erstellen mvn package # Deployment auf Payara Server # (Server muss laufen) asadmin deploy target/AuthDemo-1.0.war
📝 Wichtige Dateien erklärt
SigninServlet.java
Das Haupt-Servlet für die Authentifizierung.
Hauptmethoden:
doPost()– Verarbeitet Login-Requestsfind()– Sucht User in DatenbankgetPassword()– Hasht Passwörter mit SHA-256
Security-Features:
- ✅ Prepared Statements (SQL-Injection-Schutz)
- ✅ SHA-256 Passwort-Hashing
- ✅ Session-Management
GConnection.java
Basis-Klasse für JDBC-Verbindungen.
Funktion:
- Stellt Connection zur Datenbank her
- Lädt MySQL JDBC Driver
- Zentrale Konfiguration
Warum als Servlet-Parent? Alle Servlets erben von GConnection und können getConnection() verwenden.
Customer.java
Domain-Modell für User.
Felder:
id– Primärschlüsselemail– User-Identifikationpassword– Gehashtes Passwort
signin.jsp
Login-Formular für Benutzer.
Features:
- Email + Passwort-Eingabe
- HTML5-Validierung
- POST-Methode (Security)
signout.jsp
Logout-Funktionalität.
Funktion:
- Invalidiert die Session
- Redirect zu Login
🔐 Security-Features
1. Passwort-Hashing (SHA-256)
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
Warum?
- Passwörter werden nie im Klartext gespeichert
- Bei DB-Leak sind Passwörter unbrauchbar
2. SQL-Injection-Schutz
String sql = "SELECT * FROM customer WHERE email=? AND password=?"; PreparedStatement stmt = con.prepareStatement(sql); stmt.setString(1, email); stmt.setString(2, hashedPassword);
Warum?
?Platzhalter verhindern Code-Injection- Alle Eingaben werden escaped
3. Session-Management
HttpSession session = request.getSession();
session.setAttribute("customer", customer);
Warum?
- Zustand wird serverseitig gespeichert
- Session-ID wird als Cookie übertragen
- Automatisches Timeout
🧪 Testen
1. Login testen
- Browser:
http://localhost:8080/AuthDemo/signin.jsp - Email:
test@example.com - Passwort:
test123 - Submit → Weiterleitung zu
index.jsp
Erwartetes Ergebnis:
- Session wird erstellt
- User-Objekt in Session gespeichert
- Dashboard wird angezeigt
2. Falsches Passwort testen
- Email:
test@example.com - Passwort:
wrongpassword - Submit → Keine Session wird erstellt
Erwartetes Ergebnis:
- Login schlägt fehl
- Keine Session-Erstellung
- Keine Weiterleitung
3. SQL-Injection testen
- Email:
test@example.com' OR '1'='1 - Passwort:
irrelevant - Submit
Erwartetes Ergebnis:
- Login schlägt fehl
- Prepared Statement verhindert Injection
- Keine Sicherheitslücke
🐛 Troubleshooting
Problem: „ClassNotFoundException: com.mysql.cj.jdbc.Driver“
Lösung: MySQL JDBC Driver fehlt in pom.xml.
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
Problem: „Access denied for user ‚root’@’localhost'“
Lösung: Datenbank-Credentials in GConnection.java prüfen.
private static final String DB_USER = "root"; // Richtig? private static final String DB_PASSWORD = "root"; // Richtig?
Problem: Login funktioniert nicht
Debug:
- Passwort-Hash prüfen:
String hash = getPassword("test123");
System.out.println("Hash: " + hash);
- Mit Datenbank vergleichen:
SELECT password FROM customer WHERE email='test@example.com';
- Hashes müssen identisch sein!
Problem: Session wird nicht gespeichert
Lösung: Session vor Forward erstellen:
// ✅ RICHTIG
if(customer != null) {
HttpSession session = request.getSession(); // Hier!
session.setAttribute("customer", customer);
}
RequestDispatcher rd = request.getRequestDispatcher("index.jsp");
rd.forward(request, response);
📚 Weiterführende Resourcen
Offizielle Dokumentation:
- Jakarta Servlet API: https://jakarta.ee/specifications/servlet/
- MySQL JDBC: https://dev.mysql.com/doc/connector-j/en/
- Java Security: https://docs.oracle.com/javase/8/docs/technotes/guides/security/
Security Best Practices:
Tools:
- Online SHA-256 Generator: https://emn178.github.io/online-tools/sha256.html
- Denkt daran bei solchen Onlinetools das dort natürlich auch Rainbowtables Ihr Material bekommen
🎯 Lernziele
Nach Abschluss dieses Projekts kannst du:
- ✅ Ein Login-System mit Datenbank implementieren
- ✅ Passwörter sicher mit SHA-256 hashen
- ✅ SQL-Injection mit Prepared Statements verhindern
- ✅ Sessions für Authentifizierung nutzen
- ✅ JDBC-Verbindungen in Web-Apps verwalten
- ✅ Production-ready Security-Code schreiben
👥 Credits
Entwickelt von:
Elyndra Valen, Senior Developer
Java Fleet Systems Consulting
Kurs:
Java Web Aufbau – Tag 3 von 10
Website:
https://www.java-developer.online
📧 Support
Fragen? Probleme?
feedback@java-developer.online
Java Fleet Systems Consulting
We don’t build perfect systems. We build systems that are still maintainable in five years.
🚀 Essen-Rüttenscheid, Deutschland
💬 Real Talk: Elyndra über Authentifizierung
Freitagabend, 18:30 Uhr. Das Team-Meeting ist vorbei, aber Elyndra und Nova sind noch im Office.
Nova: „Elly, kann ich dich was fragen?“
Elyndra: „Klar, schieß los.“
Nova: „Ich hab mir überlegt… warum machen wir das eigentlich so kompliziert? Ich meine, wir könnten doch einfach die Passwörter in der Datenbank speichern und vergleichen. Warum dieser ganze Hashing-Kram?“
Elyndra: (lacht kurz) „Weißt du, das hab ich mich auch mal gefragt. Vor drei Jahren, als ich bei Java Fleet angefangen hab.“
Nova: „Und?“
Elyndra: „Franz-Martin hat mir damals eine Story erzählt. Ein Kunde von uns – großes E-Commerce-Unternehmen – wurde gehackt. Datenbank wurde geleakt. Alles.“
Nova: (schockiert) „Shit…“
Elyndra: „Ja. Aber weißt du, was das Schlimmste war? Die Passwörter waren im Klartext gespeichert. Alle 200.000 User-Accounts kompromittiert. Auf einen Schlag.“
Nova: „Okay, das ist hart.“
Elyndra: „Das ist noch nicht alles. Die meisten User nutzen dasselbe Passwort für mehrere Dienste. Email, Online-Banking, Social Media. Der Schaden ging weit über die eine Plattform hinaus.“
Nova: „Und was ist dann passiert?“
Elyndra: „Neben dem Reputationsschaden? DSGVO-Strafe. Mehrere Millionen Euro. Die Datenschutzbehörde hat argumentiert, dass das Speichern von Klartext-Passwörtern ein Verstoß gegen Artikel 32 DSGVO ist – ‚angemessene technische und organisatorische Maßnahmen‘.“
Nova: „Wait, das ist wirklich illegal?“
Elyndra: „Nicht direkt illegal im Sinne von ‚es gibt ein Gesetz gegen Klartext-Passwörter‘. Aber die DSGVO verlangt, dass du personenbezogene Daten – und Passwörter sind definitiv personenbezogen – mit ‚dem Stand der Technik‘ schützt. Und der Stand der Technik ist seit 20 Jahren: Hashing, mindestens.“
Nova: „Fuck.“
Elyndra: „Genau. Die Behörde hat gesagt: Wenn ihr wisst, dass Hashing existiert, und ihr macht es nicht, seid ihr fahrlässig. Das kann bis zu 4% vom weltweiten Jahresumsatz kosten.“
Nova: „Das ist… massive.“
Elyndra: „Yep. Deshalb hashen wir. Selbst wenn jemand unsere Datenbank klaut – die Passwörter sind unbrauchbar. Der Angreifer müsste jeden Hash einzeln cracken. Das dauert Jahre. Und wir sind DSGVO-konform.“
Nova: „Aber SHA-256 ist doch nicht perfekt, oder?“
Elyndra: (nickt) „Stimmt. Deshalb gibt’s Salt, Pepper, BCrypt, Argon2… Security ist ein Wettrüsten. Aber der erste Schritt ist: Niemals Klartext-Passwörter. Das ist nicht nur best practice – das ist rechtlich geboten.“
Nova: „Verstehe. Danke, Elly.“
Elyndra: „Kein Problem. Security ist kein Feature, das man später hinzufügt. Es ist das Fundament. Und in Europa? Es ist auch das Gesetz.“
Lesson: Passwort-Sicherheit ist nicht nur technisch sinnvoll, sondern auch rechtlich vorgeschrieben. DSGVO Artikel 32 verlangt „dem Stand der Technik entsprechende“ Sicherheitsmaßnahmen – Klartext-Passwörter erfüllen das definitiv nicht.
✅ Checkpoint: Hast du es verstanden?
Bevor du weitermachst, teste dich selbst:
Quiz:
Frage 1: Was ist der Unterschied zwischen Authentifizierung und Autorisierung?
Frage 2: Warum sollte man NIEMALS Klartext-Passwörter speichern?
Frage 3: Was ist SQL-Injection und wie verhindert man sie?
Frage 4: Was macht getPassword() und warum ist es wichtig?
Frage 5: Wie funktioniert Session-basierte Authentifizierung?
Mini-Challenge:
Aufgabe: Erweitere das SigninServlet um eine Fehlerbehandlung.
Ziel:
- Bei fehlgeschlagenem Login → Fehlerseite mit Hinweis anzeigen
- Bei DB-Fehler → Technische Fehlerseite anzeigen
- Max. 3 Login-Versuche pro Session
Hinweise:
- Prüfe
customer == nullnachfind() - Zähle Login-Versuche in Session
- Forward zu
error.jspmit Fehlermeldung
Lösung:
Die Lösung zu dieser Challenge findest du am Anfang von Tag 4! 🚀
Alternativ kannst du die Musterlösung im GitHub-Projekt checken: GitHub – Java Web Aufbau Tag 3
Geschafft? 🎉
Dann bist du bereit für die FAQ-Sektion!
❓ FAQ – Häufig gestellte Fragen
1. Warum erbt SigninServlet von GConnection statt HttpServlet?
Weil GConnection bereits von HttpServlet erbt! Java unterstützt keine Mehrfachvererbung, aber:
GConnection extends HttpServlet // GConnection hat alle Servlet-Methoden SigninServlet extends GConnection // SigninServlet erbt alles von beiden
So haben wir Servlet-Funktionalität und getConnection() in einer Klasse.
2. Kann ich mehrere User gleichzeitig einloggen?
Ja! Jeder User bekommt seine eigene Session. Sessions sind durch Session-IDs getrennt.
// User A
HttpSession sessionA = requestA.getSession(); // Session-ID: ABC123
sessionA.setAttribute("customer", customerA);
// User B
HttpSession sessionB = requestB.getSession(); // Session-ID: XYZ789
sessionB.setAttribute("customer", customerB);
Sessions sind isoliert – keine Konflikte möglich.
3. Was passiert, wenn die Datenbank down ist?
Der getConnection() Call wirft eine SQLException:
try {
Connection con = getConnection();
// ...
} catch (SQLException e) {
// DB ist down oder Connection-Problem
Logger.getLogger(...).log(Level.SEVERE, "DB Connection failed", e);
throw new ServletException("Login temporarily unavailable");
}
Best Practice: Dem User eine freundliche Fehlermeldung zeigen.
4. Ist SHA-256 ausreichend für Production?
Für kleine Projekte: Ja, mit Salt. Für Production: Besser BCrypt oder Argon2.
Warum?
- SHA-256 ist schnell → Brute-Force-Angriffe sind einfacher
- BCrypt ist langsam → Brute-Force wird ineffizient
Empfehlung: BCrypt mit Work-Factor 12-14.
5. Muss ich bei jeder Request die Datenbank abfragen?
Nein! Nach erfolgreichem Login speicherst du den User in der Session:
HttpSession session = request.getSession();
session.setAttribute("customer", customer);
Bei weiteren Requests:
Customer customer = (Customer) session.getAttribute("customer");
if(customer != null) {
// User ist eingeloggt
}
Keine DB-Abfrage nötig – Session lebt im RAM.
6. Wie verhindere ich Session-Hijacking?
Maßnahmen:
- HTTPS verwenden (TLS verschlüsselt Session-ID)
- HttpOnly Cookies (kein JavaScript-Zugriff)
- Secure Flag (nur über HTTPS senden)
- Session-ID regenerieren nach Login
// Nach erfolgreichem Login request.changeSessionId(); // Neue Session-ID
7. Was zum Henker ist ein „Salt“ und warum streut man das aufs Passwort?
Okay real talk: Salt ist kein Gewürz für dein Essen, sondern ein random String, der vor dem Hashen ans Passwort gehängt wird.
Ohne Salt:
"password123" → Hash: abc123def
Problem: Gleiche Passwörter = gleiche Hashes. Angreifer kann Rainbow Tables nutzen.
Mit Salt:
User A: "password123" + "random_salt_1" → Hash: xyz789 User B: "password123" + "random_salt_2" → Hash: qwe456
Gleiches Passwort, unterschiedliche Hashes! Rainbow Tables nutzlos.
Warum „Salt“? Weil’s das Passwort „würzt“ und es einzigartig macht. Lowkey ein Game-Changer für Security. Ngl, wer Salt nicht nutzt, läuft auf dünnem Eis.
Bonus: Pepper ist wie Salt, aber wird nicht in der DB gespeichert – bleibt auf dem Server. Extra Security-Layer. It’s giving paranoid vibes, but in a good way.
📚 Quiz-Lösungen
Hier sind die Antworten zum Quiz von oben:
Frage 1: Was ist der Unterschied zwischen Authentifizierung und Autorisierung?
Antwort:
Authentifizierung (Authentication):
- „Wer bist du?“
- Nachweis der Identität
- Beispiel: Login mit Username + Passwort
Autorisierung (Authorization):
- „Was darfst du?“
- Prüfung von Zugriffsrechten
- Beispiel: Ist der User ein Admin?
Beispiel:
- Authentifizierung: User meldet sich an → System prüft Credentials
- Autorisierung: User will Admin-Panel öffnen → System prüft Rolle
Beide sind wichtig, aber unterschiedlich!
Frage 2: Warum sollte man NIEMALS Klartext-Passwörter speichern?
Antwort:
Gründe:
- Datenbank-Leak: Bei einem Hack sind alle Passwörter kompromittiert
- Insider-Angriffe: Admins/Entwickler können Passwörter sehen
- Passwort-Wiederverwendung: User nutzen oft dasselbe Passwort für mehrere Dienste
- Compliance: DSGVO, PCI-DSS verbieten Klartext-Passwörter
- Reputation: Vertrauensverlust bei Kunden
Lösung: Passwörter hashen (SHA-256, BCrypt, Argon2)
Frage 3: Was ist SQL-Injection und wie verhindert man sie?
Antwort:
Was ist SQL-Injection? Ein Angriff, bei dem ein Angreifer SQL-Code in Eingabefelder injiziert, um die Query zu manipulieren.
Beispiel:
// Verwundbar String sql = "SELECT * FROM customer WHERE email='" + email + "'"; // Input: test@example.com' OR '1'='1 // Query wird zu: SELECT * FROM customer WHERE email='test@example.com' OR '1'='1'
Wie verhindert man es? Prepared Statements verwenden:
String sql = "SELECT * FROM customer WHERE email=?"; PreparedStatement stmt = con.prepareStatement(sql); stmt.setString(1, email); // Escaped automatisch
Prepared Statements escapen alle Sonderzeichen → Keine Injection möglich.
Frage 4: Was macht getPassword() und warum ist es wichtig?
Antwort:
Was macht getPassword()? Hasht das Klartext-Passwort mit SHA-256 und gibt einen 64-stelligen Hex-String zurück.
Code:
public String getPassword(String password) {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
StringBuffer result = new StringBuffer();
for (byte byt : hash) {
result.append(Integer.toString((byt & 0xff) + 0x100, 16).substring(1));
}
return result.toString();
}
Warum wichtig?
- Passwörter werden niemals im Klartext gespeichert
- Hashing ist irreversibel (einweg)
- Gleicher Input → Gleicher Hash (Vergleich möglich)
Verwendung:
// Bei Registrierung
String hash = getPassword("user_password");
// In DB speichern: hash
// Bei Login
String inputHash = getPassword(input_password);
// Mit DB vergleichen: inputHash == storedHash
Frage 5: Wie funktioniert Session-basierte Authentifizierung?
Antwort:
Flow:
- User sendet Login-Daten (POST)
- Servlet prüft Credentials gegen DB
- Bei Erfolg: User-Objekt in Session speichern
- Session-ID wird als Cookie an Client gesendet
- Bei weiteren Requests: Session-ID wird mitgeschickt
- Server erkennt User anhand Session-ID
Code:
// Nach erfolgreichem Login
HttpSession session = request.getSession();
session.setAttribute("customer", customer);
// Bei weiteren Requests
Customer customer = (Customer) session.getAttribute("customer");
if(customer != null) {
// User ist eingeloggt
}
Vorteile:
- Keine DB-Abfrage bei jeder Request
- Serverseitig gespeichert (sicherer als Cookies)
- Automatisches Timeout möglich
🎉 Tag 3 geschafft!
Slay! Du hast es geschafft! 🚀
Real talk: Authentifizierung ist kein einfaches Thema. Es gibt so viele Dinge, die schiefgehen können – SQL-Injection, schwache Passwörter, Session-Hijacking. Aber du hast durchgezogen und jetzt ein production-ready Login-System!
Das hast du heute gerockt:
- ✅ Passwort-Hashing mit SHA-256 implementiert
- ✅ SQL-Injection mit Prepared Statements verhindert
- ✅ Session-Management verstanden
- ✅ Login-Flow von A bis Z gebaut
Honestly? Du bist jetzt weiter als viele Devs, die Login-Systeme bauen ohne die Security-Basics zu kennen. Das ist huge.
Main Character Energy: Unlocked! ✨
Wie geht’s weiter?
Morgen (Tag 4): Container-Managed Securi
⚖️ DSGVO & Rechtliche Aspekte
Ist Passwort-Hashing rechtlich vorgeschrieben?
Kurze Antwort: Ja, in der EU.
DSGVO Artikel 32 – Sicherheit der Verarbeitung:
„Der Verantwortliche […] trifft geeignete technische und organisatorische Maßnahmen, um ein dem Risiko angemessenes Schutzniveau zu gewährleisten.“
Was bedeutet das konkret?
- Passwörter sind personenbezogene Daten
- Sie identifizieren eine Person
- Sie unterliegen dem Datenschutz
- „Stand der Technik“ ist entscheidend
- Hashing ist seit 20+ Jahren Standard
- Klartext = nicht „Stand der Technik“
- Gerichte sehen das als fahrlässig
- Bei Verstößen drohen:
- Bußgelder bis 20 Millionen Euro ODER
- 4% des weltweiten Jahresumsatzes (je nachdem, was höher ist)
- Schadensersatzforderungen von Betroffenen
- Reputationsschaden
Beispiel aus der Praxis:
2019 wurde ein deutsches Unternehmen zu 14,5 Millionen Euro Strafe verurteilt, weil Passwörter im Klartext gespeichert wurden. Die Begründung: „Es ist allgemein bekannt, dass Passwörter verschlüsselt oder gehasht werden müssen.“
Minimum-Anforderungen für DSGVO-Konformität:
- ✅ Passwort-Hashing (SHA-256 oder besser)
- ✅ Mit Salt (gegen Rainbow Tables)
- ✅ HTTPS für Übertragung
- ✅ Sichere Session-Verwaltung
- ✅ Dokumentierte Security-Maßnahmen
Empfehlung für Production:
- BCrypt oder Argon2 statt SHA-256
- Multi-Faktor-Authentifizierung
- Regelmäßige Security-Audits
- Incident Response Plan

