Leitlinien

Authentifizierung und Autorisierung

Das Thema Authentifizierung (AuthN) und Autorisierung (AuthZ) ist aufgrund der Häufigkeit von Schwachstellen, bei denen eine der beiden Komponenten angreifbar ist, äußerst wichtig. Da sie so regelmäßig aufzutreten scheinen, bedeutet das normalerweise, dass es eine gewisse Unsicherheit darüber gibt, was sie sind oder sogar, was sie verursacht. 

Zur Erinnerung: Jeder Begriff umfasst die folgenden Punkte:

  • Authentifizierung: Wer ist der Nutzer? 
  • Berechtigung: Worauf soll der Benutzer Zugriff haben? 

Wir werden sie im Folgenden getrennt betrachten.

Authentifizierung (Identifizierung und Authentifizierungsfehler)

Eine unsachgemäße Authentifizierung kann eine Vielzahl von Schwachstellen abdecken, wie z. B.:

  • Das Fehlen einer Authentifizierung auf einer bestimmten Seite/Endpunkt
  • Mangelnder Schutz gegen Brute-Force-Angriffe (Credentials stuffing)
  • Unsichere Verfahren zur Wiederherstellung von Konten/Passwörtern
  • Unsichere Erzeugung, Validierung, Ablauf, Übertragung oder Speicherung von Authentifizierungstoken
  • Falsche oder fehlende Validierung, dass der Benutzer sich mit 2FA authentifiziert hat (falls zutreffend)

Der erste Punkt auf der Liste (fehlende Authentifizierung) ist bei weitem das häufigste Problem, das in der Praxis beobachtet wird. In vielen Fällen muss ein Entwickler die für eine Seite oder einen Endpunkt erforderliche Authentifizierungsstufe ausdrücklich angeben/konfigurieren, und dieser Schritt kann leicht übersehen werden. 

Es ist eine gute Praxis, dafür zu sorgen, dass ein System geschlossen ausfällt, anstatt offen auszufallen. Anstatt also jeden Endpunkt mit der Information zu versehen, dass eine authentifizierte Benutzersitzung erforderlich ist, sollte die Standardeinstellung sein, dass alle Routen eine authentifizierte Benutzersitzung erfordern, es sei denn, dies wurde ausdrücklich außer Kraft gesetzt. Auf diese Weise lässt sich die Fehleranfälligkeit drastisch verringern.

Autorisierung (gebrochene Zugangskontrolle)

Autorisierungsprobleme können sich auf verschiedene Weise äußern, die sehr verbreitet sind:

  • Unsichere direkte Objektreferenzen (IDOR)
  • Fehlende Zugriffskontrolle auf Funktionsebene (fehlende AuthZ)
  • Privilegienerweiterung (horizontal oder vertikal)

Unsichere direkte Objektreferenzen

Objekte haben in der Regel eindeutige Bezeichner (IDs), die als Schlüssel verwendet werden, um auf sie zu verweisen. Wenn ein Benutzer eine Anfrage sendet, um eine Bestellung, ein Konto oder etwas Ähnliches einzusehen, enthält sie in der Regel diese ID. Ein "unsicherer direkter Objektverweis" tritt auf, wenn die Anwendung nicht überprüfen kann, ob der Benutzer (oder das Fehlen eines solchen) in der Lage sein sollte, auf dieses spezifische Objekt zuzugreifen.

Fehlende Zugriffskontrolle auf Funktionsebene 

Eine weitere sehr häufige Schwachstelle ist das Fehlen von Berechtigungsprüfungen für eine Seite oder einen Endpunkt (im Gegensatz zu einem Objekt). 

Je nach verwendetem Framework ist es üblich, dass Entwickler entweder die Berechtigung im Handler prüfen oder den Endpunkt annotieren und die für den Aufruf des Endpunkts erforderlichen Anforderungen angeben müssen. 

Leider sind diese zusätzlichen Schritte auch sehr leicht zu vergessen, was oft erklärt, wie es zu einigen Autorisierungsschwachstellen kommt.

Empfehlungen

Standardmäßig geschlossen und nicht offen

Sowohl bei der Authentifizierung als auch bei der Autorisierung ist der Grundsatz wichtig, dass die Standardeinstellung geschlossen statt offen ist. 

Je nach Sprache/Framework ist es eine gute Praxis, sicherzustellen, dass die Standardeinstellung für alle Routen in Ihrer Anwendung eine authentifizierte Sitzung mit den höchstmöglichen Rollen oder Berechtigungen erfordert. Auf diese Weise wird ein Entwickler gezwungen, die Anforderungen für die Route zu überschreiben. 

cs

// Ensure the default behaviour is to authenticate requests, and check if they are admin
[Authenticate]
[Authorize("Admin")]
public class SecureController : Controller
{

}

public class MyController : SecureController
{

    // Overrides the Authorize attribute inherited to allow any user to access the page
    [Authorize("User")]
    public Page ShowUserProfile() {
        
    }   

    // Can only be accessed by an Admin user
    public Page ShowAdminPage() { 

   }

    // Overrides the Authenticate and Authorize attribute to allow ME
    [AllowAnonymous]
    public Page ShowLoginPage() {
       
    } 

}

Durchsetzung von Berechtigungsprüfungen in Diensten

Beim Zugriff auf Daten muss unbedingt sichergestellt werden, dass alle Datenzugriffe die entsprechenden Zugriffs- und Berechtigungsprüfungen auf einheitliche Weise durchführen. Dies wird in der Regel durch die Verwendung von Domänendiensten erreicht.

Weitere Beispiele

Im Folgenden finden Sie eine kurze Sammlung von Beispielen, die den Unterschied zwischen sicherer und unsicherer Authentifizierung und Autorisierung verdeutlichen. 

C# - unsicher

Fehlende Authentifizierung

public class AdminController : Controller
{

    // INSECURE: Does not check whether the user is logged in before showing an Admin page
    public Page ShowAdminPage() {

    }

}

Fehlende Genehmigung

[Authenticate]
public class AdminController : Controller
{

    // INSECURE: Does not check the Authorization of the user before showing an Admin page public Page ShowAdminPage() {

    }

}

C# - sicher

[Authenticate]
[Authorize("Admin")]
public class AdminController : Controller
{

    // SECURE: Both checks that the user is logged in, and has the Admin role
    public Page ShowAdminPage() {

    }

}