Skip to content

Kapitel 15: MySQL Sicherheit ⭐⭐

Sicherheit ist extrem wichtig für Datenbanken! In diesem Kapitel lernst du, wie man MySQL sicher macht.

15.1 SQL-Injection (SQL-Einschleusung) ⭐⭐ Wichtig!

SQL-Injection ist eine der häufigsten Sicherheitslücken bei Webseiten.

Was ist SQL-Injection?

Angreifer können bösartigen SQL-Code über Eingabefelder einschleusen.

Beispiel (Unsicher):

php
// ❌ Gefährlich! (SQL-Injection möglich)
$username = $_POST['username'];
$passwort = $_POST['passwort'];

$sql = "SELECT * FROM users 
         WHERE username = '$username' 
           AND passwort = '$passwort'";

// Angreifer gibt bei Username ein: ' OR '1'='1
// SQL wird zu:
// SELECT * FROM users WHERE username = '' OR '1'='1' AND passwort = '...'
// → Logged sich OHNE Passwort ein!

Gefahren durch SQL-Injection

  • ✅ Datenklau (Benutzernamen, Passwörter, Kreditkartennummern)
  • ✅ Datenmanipulation (Löschen, Ändern von Daten)
  • ✅ Datensatz-Löschung (komplettes Löschen der Tabelle)
  • ✅ Administrator-Rechte erlangen

Schutzmaßnahmen ⭐⭐

1. Parametrisierte Abfragen (Prepared Statements) - Wichtigste Methode!

PHP-Beispiel (Sicher):

php
 Sicher! (Prepared Statements verwenden)
$stmt = $pdo->prepare("SELECT * FROM users 
                         WHERE username = :username 
                           AND passwort = :passwort");
$stmt->execute([
    'username' => $username,
    'passwort' => $passwort
]);
// → SQL-Injection unmöglich!

Java-Beispiel (Sicher):

java
// ✅ Sicher! (Prepared Statements verwenden)
String sql = "SELECT * FROM users WHERE username = ? AND passwort = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, passwort);
ResultSet rs = stmt.executeQuery();

2. Eingaben validieren und bereinigen

php
// ✅ Sicher! (Eingabe validieren)
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
if (empty($username)) {
    die('Ungültiger Benutzername!');
}

3. Keine dynamischen SQL-Abfragen bauen

php
// ❌ Gefährlich!
$sql = "SELECT * FROM users WHERE username = '" . $_POST['username'] . "'";

// ✅ Sicher!
$sql = "SELECT * FROM users WHERE username = ?";

4. Fehlermeldungen unterdrücken

php
// ❌ Gefährlich! (Zeigt Tabellenstruktur preis)
mysql_query($sql) or die(mysql_error());

// ✅ Sicher!
mysql_query($sql) or die('Ein Fehler ist aufgetreten.');

15.2 Datenbank-Berechtigungsverwaltung (Für Einsteiger: Grundlegendes wissen)

MySQL verfügt über ein leistungsstarkes Berechtigungssystem.

1. Benutzer erstellen

sql
-- Benutzer erstellen
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'starkes_passwort_123';

-- Benutzer mit beliebigem Host erstellen (⚠️ Vorsicht!)
CREATE USER 'app_user'@'%' IDENTIFIED BY 'starkes_passwort_123';

2. Berechtigungen gewähren (GRANT)

sql
-- Alle Berechtigungen auf alle Datenbanken gewähren (⚠️ Nicht empfohlen!)
GRANT ALL PRIVILEGES ON *.* TO 'app_user'@'localhost';

-- Nur Lesezugriff auf eine Datenbank gewähren
GRANT SELECT ON shop_db.* TO 'app_user'@'localhost';

-- Lese- und Schreibzugriff gewähren
GRANT SELECT, INSERT, UPDATE, DELETE ON shop_db.* TO 'app_user'@'localhost';

-- Berechtigungen aktivieren
FLUSH PRIVILEGES;

3. Berechtigungen entziehen (REVOKE)

sql
-- Eine Berechtigung entziehen
REVOKE DELETE ON shop_db.* FROM 'app_user'@'localhost';

-- Alle Berechtigungen entziehen
REVOKE ALL PRIVILEGES ON *.* FROM 'app_user'@'localhost';

4. Benutzer löschen

sql
DROP USER 'app_user'@'localhost';

Best Practices für Berechtigungen

  • Prinzip der geringsten Rechte (Least Privilege): Nur die unbedingt notwendigen Berechtigungen gewähren
  • Keine Root-Berechtigungen für Anwendungen: Erstelle separate Benutzer für jede Anwendung
  • Starke Passwörter: Verwende komplexe Passwörter für Datenbankbenutzer
  • Berechtigungen regelmäßig überprüfen

15.3 Datenbank-Backup und -Wiederherstellung (Kernpunkt - Datenverlust verhindern)

Backups sind lebenswichtig! Wenn die Datenbank beschädigt wird oder Daten verloren gehen, ist ein Backup die einzige Rettung.

1. Backup erstellen (mysqldump)

Befehlzeile (Terminal / Eingabeaufforderung):

bash
# Ganze Datenbank sichern
mysqldump -u root -p shop_db > backup_shop_db.sql

# Mehrere Datenbanken sichern
mysqldump -u root -p --databases shop_db blog_db > backup_mehrere.sql

# Alle Datenbanken sichern
mysqldump -u root -p --all-databases > backup_alle.sql

Mit phpMyAdmin:

  1. Datenbank auswählen
  2. "Export" klicken;
  3. "Schnell" oder "Benutzerdefiniert" wählen;
  4. "Ausführen" klicken → .sql-Datei herunterladen.

2. Wiederherstellung (Restore)

Befehlzeile:

bash
# Wiederherstellung über die Befehlzeile
mysql -u root -p shop_db < backup_shop_db.sql

Mit phpMyAdmin:

  1. Eine neue Datenbank erstellen (oder eine vorhandene auswählen);
  2. "Import" klicken;
  3. .sql-Datei auswählen;
  4. "Ausführen" klicken.

3. Automatisierte Backups (Cron Job / Task Scheduler)

Linux (Cron Job):

bash
# Jedes Mal um 2 Uhr morgens ein Backup durchführen
0 2 * * * mysqldump -u root -pMEIN_PASSWORT shop_db > /backups/shop_$(date +\%Y\%m\%d).sql

Windows (Task Scheduler):

  1. Einen Batch-Skript (backup.bat) erstellen:
    batch
    @echo off
    set DATE=%date:~6,4%%date:~3,2%%date:~0,2%
    mysqldump -u root -pMEIN_PASSWORT shop_db > C:\backups\shop_%DATE%.sql
  2. Den Taskplaner verwenden, um backup.bat regelmäßig auszuführen.

Praxisbeispiel: SQL-Injection verhindern

Szenario: Erstelle ein sicheres Login-Skript.

Unsicheres Skript (❌ Gefährlich!)

php
// login_unsafe.php
$username = $_POST['username'];
$passwort = $_POST['passwort'];

$sql = "SELECT * FROM users WHERE username = '$username' AND passwort = '$passwort'";
$result = mysqli_query($conn, $sql);

Sicheres Skript (✅ Mit Prepared Statements)

php
// login_safe.php
$username = $_POST['username'];
$passwort = $_POST['passwort'];

// 1. Prepared Statement vorbereiten
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND passwort = ?");
$stmt->bind_param("ss", $username, $passwort);  // "ss" = zwei Strings

// 2. Ausführen
$stmt->execute();

// 3. Ergebnis abrufen
$result = $stmt->get_result();

Häufige Fehler für Einsteiger

Fehler 1: SQL-Injection ignorieren

php
// ❌ Falsch: Eingabe direkt in SQL einfügen
$sql = "SELECT * FROM users WHERE username = '" . $_GET['user'] . "'";

// ✅ Richtig: Prepared Statements verwenden
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$_GET['user']]);

Fehler 2: Root-Benutzer in Anwendungen verwenden

sql
-- ❌ Falsch: Root-Benutzer in der Anwendung verwenden
$conn = new mysqli('localhost', 'root', 'root_passwort', 'shop_db');

-- ✅ Richtig: separaten Benutzer mit begrenzten Berechtigungen erstellen
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'starkes_passwort';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop_db.* TO 'app_user'@'localhost';

Fehler 3: Keine Backups erstellen

bash
# ❌ Falsch: Niemals ein Backup erstellen!
# → Bei Festplattenausfall: ALLE DATEN WEG!

# ✅ Richtig: Regelmäßig Backups erstellen!
mysqldump -u root -p shop_db > backup_$(date +%Y%m%d).sql

Zusammenfassung

In diesem Kapitel hast du gelernt:

  • ✅ Was SQL-Injection ist und wie gefährlich sie ist
  • ✅ SQL-Injection zu verhindern (Prepared Statements)
  • ✅ MySQL-Berechtigungen zu verwalten (Benutzer, GRANT, REVOKE)
  • ✅ Datenbank-Backups zu erstellen (mysqldump)
  • ✅ Datenbanken aus Backups wiederherzustellen
  • ✅ Automatisierte Backups einzurichten

Übungen

  1. Theorie: Was ist SQL-Injection und wie kann man sie verhindern?
  2. Praxis: Erstelle ein sicheres PHP-Login-Skript mit Prepared Statements
  3. SQL: Erstelle einen neuen MySQL-Benutzer webapp mit nur Lese- und Schreibzugriff auf test_db
  4. Praxis: Erstelle ein manuelles Backup deiner shop_db Datenbank
  5. Praxis: Stelle die Datenbank aus dem Backup wieder her

Nächstes Kapitel

Im nächsten Kapitel lernen wir MySQL-Leistungsoptimierung - wie man Indizes verwendet, SQL-Abfragen optimiert und die Ausführungspläne analysiert!

Frei für alle Anfänger