In diesem Kapitel behandeln wir die wichtigsten Sicherheitsaspekte bei der Arbeit mit SQL-Datenbanken. Besonderes Augenmerk liegt dabei auf der Prävention von SQL-Injection-Angriffen.
SQL Injection ist eine der häufigsten und gefährlichsten Angriffsmethoden auf Datenbanken. Dabei werden SQL-Befehle in Eingabefelder eingeschleust, die dann von der Datenbank ausgeführt werden.
Angenommen, wir haben folgenden unsicheren Code:
$username = $_POST['username'];
$query = "SELECT * FROM users WHERE username = '$username'";Ein Angreifer könnte folgende Eingabe machen:
' OR '1'='1Der resultierende SQL-Befehl wäre dann:
SELECT * FROM users WHERE username = '' OR '1'='1'Dieser Befehl würde alle Benutzer zurückgeben, da die Bedingung
'1'='1' immer wahr ist.
Ein Angreifer könnte auch versuchen:
'; DROP TABLE users; --oder
' UNION SELECT username, password FROM users; --Die sicherste Methode zur Verhinderung von SQL Injection:
// PHP mit PDO
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
// PHP mit MySQLi
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();Falls Prepared Statements nicht möglich sind:
$username = mysqli_real_escape_string($connection, $username);-- MySQL
PREPARE stmt FROM 'SELECT * FROM users WHERE username = ?';
SET @username = 'john';
EXECUTE stmt USING @username;
DEALLOCATE PREPARE stmt;Benutzer sollten nur die minimal notwendigen Rechte haben:
-- Beispiel für eingeschränkte Rechte
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'password';
GRANT SELECT, INSERT ON database.table TO 'app_user'@'localhost';// Beispiel für Eingabevalidierung
if (!preg_match("/^[a-zA-Z0-9]+$/", $username)) {
die("Ungültige Zeichen im Benutzernamen");
}Produktive Systeme sollten keine detaillierten Fehlermeldungen anzeigen:
// Schlechtes Beispiel
catch (Exception $e) {
echo $e->getMessage(); // Zeigt möglicherweise sensible Informationen
}
// Gutes Beispiel
catch (Exception $e) {
log_error($e); // Fehler intern loggen
echo "Ein Fehler ist aufgetreten"; // Generische Meldung für Benutzer
}-- Beispiel für Verschlüsselung
CREATE TABLE users (
username VARCHAR(50),
password_hash CHAR(60), -- Für bcrypt Hashes
email VARCHAR(100) ENCRYPTED
);CREATE TABLE audit_log (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
action VARCHAR(50),
table_name VARCHAR(50),
record_id INT,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
details TEXT
);
-- Beispiel für einen Trigger
DELIMITER //
CREATE TRIGGER users_audit_insert
AFTER INSERT ON users
FOR EACH ROW
BEGIN
INSERT INTO audit_log (user_id, action, table_name, record_id)
VALUES (NEW.id, 'INSERT', 'users', NEW.id);
END//
DELIMITER ;-- Beispiel für Sicherheitscheck-Abfragen
SELECT user, host FROM mysql.user; -- Überprüfung der Benutzer
SHOW GRANTS; -- Anzeige der Berechtigungen
SELECT * FROM audit_log WHERE action = 'FAILED_LOGIN'; -- Überprüfung fehlgeschlagener Anmeldeversuche