Standardauthentifizierung in ASP.NET-Web-API

von Mike Wasson

Die Standardauthentifizierung ist in RFC 2617, HTTP-Authentifizierung: Standard- und Digestzugriffsauthentifizierung definiert.

Nachteile

  • Benutzeranmeldeinformationen werden in der Anforderung gesendet.
  • Anmeldeinformationen werden als Klartext gesendet.
  • Anmeldeinformationen werden bei jeder Anforderung gesendet.
  • Keine Möglichkeit zum Abmelden, außer durch Beenden der Browsersitzung.
  • Anfällig für websiteübergreifende Anforderungsfälschung (CSRF); erfordert Maßnahmen zur Bekämpfung der CSRF.

Vorteile

  • Internetstandard.
  • Unterstützt von allen gängigen Browsern.
  • Relativ einfaches Protokoll.

Die Standardauthentifizierung funktioniert wie folgt:

  1. Wenn eine Anforderung eine Authentifizierung erfordert, gibt der Server 401 (nicht autorisiert) zurück. Die Antwort enthält einen WWW-Authenticate-Header, der angibt, dass der Server die Standardauthentifizierung unterstützt.
  2. Der Client sendet eine weitere Anforderung mit den Clientanmeldeinformationen im Autorisierungsheader. Die Anmeldeinformationen sind als Zeichenfolge "name:password" formatiert, base64-codiert. Die Anmeldeinformationen sind nicht verschlüsselt.

Die Standardauthentifizierung erfolgt im Kontext eines "Bereichs". Der Server enthält den Namen des Bereichs in den WWW-Authenticate-Header. Die Anmeldeinformationen des Benutzers sind innerhalb dieses Bereichs gültig. Der genaue Bereich eines Bereichs wird vom Server definiert. Sie können beispielsweise mehrere Bereiche definieren, um Ressourcen zu partitionieren.

Diagramm der Standardauthentifizierung

Da die Anmeldeinformationen unverschlüsselt gesendet werden, ist die Standardauthentifizierung nur über HTTPS sicher. Weitere Informationen finden Sie unter Arbeiten mit SSL in der Web-API.

Die Standardauthentifizierung ist auch anfällig für CSRF-Angriffe. Nachdem der Benutzer Anmeldeinformationen eingegeben hat, sendet der Browser sie automatisch bei nachfolgenden Anforderungen für die Dauer der Sitzung an dieselbe Domäne. Dies schließt AJAX-Anforderungen ein. Weitere Informationen finden Sie unter Verhindern von CsrF-Angriffen (Cross-Site Request Forgery).

Standardauthentifizierung mit IIS

IIS unterstützt die Standardauthentifizierung, aber es gibt eine Einschränkung: Der Benutzer wird mit seinen Windows-Anmeldeinformationen authentifiziert. Das bedeutet, dass der Benutzer über ein Konto in der Domäne des Servers verfügen muss. Bei einer öffentlich zugänglichen Website möchten Sie sich in der Regel bei einem ASP.NET-Mitgliedschaftsanbieter authentifizieren.

Um die Standardauthentifizierung mithilfe von IIS zu aktivieren, legen Sie den Authentifizierungsmodus im Web.config Ihres ASP.NET-Projekts auf "Windows" fest:

<system.web>
    <authentication mode="Windows" />
</system.web>

In diesem Modus verwendet IIS Windows-Anmeldeinformationen zur Authentifizierung. Darüber hinaus müssen Sie die Standardauthentifizierung in IIS aktivieren. Wechseln Sie im IIS-Manager zu Featureansicht, wählen Sie Authentifizierung aus, und aktivieren Sie die Standardauthentifizierung.

Abbildung des IS-Managers Dashboard

Fügen Sie in Ihrem Web-API-Projekt das [Authorize] Attribut für alle Controlleraktionen hinzu, die eine Authentifizierung erfordern.

Ein Client authentifiziert sich selbst, indem er den Autorisierungsheader in der Anforderung festlegt. Browserclients führen diesen Schritt automatisch aus. Nichtbrowserclients müssen den Header festlegen.

Standardauthentifizierung mit benutzerdefinierter Mitgliedschaft

Wie bereits erwähnt, verwendet die in IIS integrierte Standardauthentifizierung Windows-Anmeldeinformationen. Das bedeutet, dass Sie Konten für Ihre Benutzer auf dem Hostingserver erstellen müssen. Bei einer Internetanwendung werden Benutzerkonten jedoch in der Regel in einer externen Datenbank gespeichert.

Der folgende Code zeigt ein HTTP-Modul, das die Standardauthentifizierung ausführt. Sie können einen ASP.NET Mitgliedschaftsanbieter problemlos anschließen, indem Sie die -Methode ersetzen, bei der CheckPassword es sich in diesem Beispiel um eine Dummymethode handelt.

In Web-API 2 sollten Sie erwägen, anstelle eines HTTP-Moduls einen Authentifizierungsfilter oder eine OWIN-Middleware zu schreiben.

namespace WebHostBasicAuth.Modules
{
    public class BasicAuthHttpModule : IHttpModule
    {
        private const string Realm = "My Realm";

        public void Init(HttpApplication context)
        {
            // Register event handlers
            context.AuthenticateRequest += OnApplicationAuthenticateRequest;
            context.EndRequest += OnApplicationEndRequest;
        }

        private static void SetPrincipal(IPrincipal principal)
        {
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
            {
                HttpContext.Current.User = principal;
            }
        }

        // TODO: Here is where you would validate the username and password.
        private static bool CheckPassword(string username, string password)
        {
            return username == "user" && password == "password";
        }

        private static void AuthenticateUser(string credentials)
        {
            try
            {
                var encoding = Encoding.GetEncoding("iso-8859-1");
                credentials = encoding.GetString(Convert.FromBase64String(credentials));

                int separator = credentials.IndexOf(':');
                string name = credentials.Substring(0, separator);
                string password = credentials.Substring(separator + 1);

                if (CheckPassword(name, password))
                {
                    var identity = new GenericIdentity(name);
                    SetPrincipal(new GenericPrincipal(identity, null));
                }
                else
                {
                    // Invalid username or password.
                    HttpContext.Current.Response.StatusCode = 401;
                }
            }
            catch (FormatException)
            {
                // Credentials were not formatted correctly.
                HttpContext.Current.Response.StatusCode = 401;
            }
        }

        private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
        {
            var request = HttpContext.Current.Request;
            var authHeader = request.Headers["Authorization"];
            if (authHeader != null)
            {
                var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);

                // RFC 2617 sec 1.2, "scheme" name is case-insensitive
                if (authHeaderVal.Scheme.Equals("basic",
                        StringComparison.OrdinalIgnoreCase) &&
                    authHeaderVal.Parameter != null)
                {
                    AuthenticateUser(authHeaderVal.Parameter);
                }
            }
        }

        // If the request was unauthorized, add the WWW-Authenticate header 
        // to the response.
        private static void OnApplicationEndRequest(object sender, EventArgs e)
        {
            var response = HttpContext.Current.Response;
            if (response.StatusCode == 401)
            {
                response.Headers.Add("WWW-Authenticate",
                    string.Format("Basic realm=\"{0}\"", Realm));
            }
        }

        public void Dispose() 
        {
        }
    }
}

Um das HTTP-Modul zu aktivieren, fügen Sie Ihrer web.config-Datei im Abschnitt system.webServer Folgendes hinzu:

<system.webServer>
    <modules>
      <add name="BasicAuthHttpModule" 
        type="WebHostBasicAuth.Modules.BasicAuthHttpModule, YourAssemblyName"/>
    </modules>

Ersetzen Sie "YourAssemblyName" durch den Namen der Assembly (ohne die Erweiterung "dll").

Sie sollten andere Authentifizierungsschemas deaktivieren, z. B. Forms oder Die Windows-Authentifizierung.