OWASP Top 10 2010: Was Java- und PHP-Entwickler mitnehmen sollten

Keine Zeit? Hier die Kurzversion in 30 Sekunden.
- Die OWASP Top 10 sind eine Liste der häufigsten Sicherheitsrisiken bei Webanwendungen, die Version 2010 ist seit April final.
- Neu sind Security Misconfiguration und Unvalidated Redirects, Malicious File Execution und Information Leakage sind rausgefallen.
- Gegen Injection helfen Prepared Statements, gegen CSRF ein Token pro Formular.
- Die Liste ist ein guter Fahrplan, um eigene Projekte durchzugehen.
Am 19. April hat OWASP die finale Fassung der Top 10 für 2010 veröffentlicht. Das ist eine Liste mit den zehn häufigsten Risiken für Webanwendungen, und ich habe sie mir mal Punkt für Punkt angeschaut, mit Blick auf PHP und Java, weil ich gerade mit beidem zu tun habe. Zwei Punkte hatte ich hier schon behandelt: SQL-Injection mit PDO und XSS mit htmlspecialchars. Bei diesen beiden fasse ich mich deshalb kurz.
A1: Injection
Der Klassiker. Eingaben dürfen nie in einen Befehl hineingebaut werden. In Java heißt die Lösung PreparedStatement:
PreparedStatement ps = con.prepareStatement(
"SELECT * FROM benutzer WHERE name = ? AND pass = ?");
ps.setString(1, name);
ps.setString(2, passHash);
ResultSet rs = ps.executeQuery();In PHP macht man das mit PDO. Gilt übrigens auch für Shell-Befehle (escapeshellarg) und LDAP.
A2: Cross-Site Scripting (XSS)
Alles, was ausgegeben wird, wird maskiert: htmlspecialchars($text, ENT_QUOTES, 'UTF-8') in PHP, in Java zum Beispiel mit <c:out> in JSP.
A3: Broken Authentication and Session Management
Session-ID nach dem Login neu vergeben, Sessions beim Logout wirklich zerstören, die ID nie in der URL.
<?php
session_start();
// nach erfolgreichem Login:
session_regenerate_id(true);A4: Insecure Direct Object References
Wer rechnung.php?id=17 aufruft, darf nicht automatisch auch die 18 sehen. Bei jedem Zugriff prüfen, ob die Ressource dem angemeldeten Benutzer gehört, nicht nur beim Anzeigen der Liste.
A5: Cross-Site Request Forgery (CSRF)
Ein fremdes Formular oder Bild löst im Namen des eingeloggten Benutzers eine Aktion aus. Abhilfe ist ein zufälliges Token, das in der Session liegt und im Formular mitgeschickt wird:
<?php
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = md5(uniqid(mt_rand(), true));
}
?>
<form method="post" action="loeschen.php">
<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">
<input type="submit" value="Löschen">
</form>Beim Absenden vergleicht man dann:
<?php
session_start();
if (!isset($_POST['token']) || $_POST['token'] !== $_SESSION['token']) {
die('Ungültige Anfrage');
}A6: Security Misconfiguration
Neu in der Liste. Standardpasswörter, offene Verwaltungsoberflächen, display_errors im Produktivbetrieb, nicht eingespielte Updates. Das ist unspektakulär und kommt trotzdem ständig vor. Bei PHP zählt display_errors = Off auf dem Live-System dazu, bei Java Tomcat-Manager und Beispielanwendungen.
A7: Insecure Cryptographic Storage
Passwörter nicht im Klartext speichern, und ein einfaches md5($pass) ohne Salt ist auch nicht mehr gut. Besser ein individuelles Salt pro Benutzer und ein stärkerer Hash:
<?php
$salt = substr(md5(uniqid(mt_rand(), true)), 0, 16);
$hash = hash('sha256', $salt . $passwort);
// salt und hash speichernDas ist keine Wunderlösung, aber deutlich besser als reines MD5. Ich muss mich hier selbst noch weiter einlesen.
A8: Failure to Restrict URL Access
Nur den Menüpunkt zu verstecken reicht nicht. Jede Seite und jede Aktion braucht eine eigene Berechtigungsprüfung. Wer die URL der Admin-Seite errät, darf nicht einfach hinein.
A9: Insufficient Transport Layer Protection
Login und Session-Cookie gehören über HTTPS. Den Cookie zusätzlich mit dem secure-Flag und httponly setzen:
<?php
session_set_cookie_params(0, '/', '', true, true);
session_start();A10: Unvalidated Redirects and Forwards
Ein Parameter wie weiter.php?url=... darf nicht blind weiterleiten, sonst baut jemand einen Link auf eure Domain, der beim Opfer auf einer Phishing-Seite landet. Ziel gegen eine feste Liste prüfen, oder besser nur eine Kennung statt einer URL übergeben.
Als Checkliste nutzen
Ich nehme die Liste als Checkliste, wenn ich ein Projekt durchsehe. Nicht alles trifft jede Anwendung gleich, aber man merkt schnell, wo man schlampig war. Habt ihr eure Projekte schon mal damit abgeklopft?
Christian Ackermann
Softwareentwickler (C++, C, Java, C#) aus der Oberpfalz, bloggt seit 2001 über Linux, Technik und Kochen.