Základní ověřování ve webovém rozhraní API ASP.NET

Mike Wasson

Základní ověřování je definováno v DOKUMENTU RFC 2617, Ověřování HTTP: Základní ověřování a ověřování přístupu hodnotou hash.

Nevýhody

  • Přihlašovací údaje uživatele se odesílají v požadavku.
  • Přihlašovací údaje se odesílají jako prostý text.
  • Přihlašovací údaje se odesílají s každým požadavkem.
  • Žádný způsob, jak se odhlásit, s výjimkou ukončení relace prohlížeče.
  • Zranitelnost vůči padělání požadavků napříč weby (CSRF); vyžaduje opatření proti CSRF.

Výhody

  • Internetový standard.
  • Podporované ve všech hlavních prohlížečích.
  • Relativně jednoduchý protokol.

Základní ověřování funguje takto:

  1. Pokud požadavek vyžaduje ověření, server vrátí chybu 401 (Neautorizováno). Odpověď obsahuje hlavičku WWW-Authenticate, která označuje, že server podporuje základní ověřování.
  2. Klient odešle další požadavek s přihlašovacími údaji klienta v autorizační hlavičce. Přihlašovací údaje jsou formátované jako řetězec "name:password" s kódováním base64. Přihlašovací údaje nejsou šifrované.

Základní ověřování se provádí v kontextu "sféry". Server obsahuje název sféry v hlavičce WWW-Authenticate. Přihlašovací údaje uživatele jsou platné v rámci této sféry. Přesný rozsah sféry definuje server. Můžete například definovat několik sfér za účelem dělení prostředků.

Diagram základního ověřování

Vzhledem k tomu, že se přihlašovací údaje odesílají v nezašifrované podobě, základní ověřování je bezpečné pouze přes protokol HTTPS. Viz Práce s SSL ve webovém rozhraní API.

Základní ověřování je také zranitelné vůči útokům CSRF. Jakmile uživatel zadá přihlašovací údaje, prohlížeč je po dobu trvání relace automaticky odešle při následných požadavcích do stejné domény. To zahrnuje požadavky AJAX. Viz Prevence útoků CSRF (Cross-Site Request Forgery).

Základní ověřování se službou IIS

Služba IIS podporuje základní ověřování, ale existuje upozornění: Uživatel je ověřený pomocí svých přihlašovacích údajů systému Windows. To znamená, že uživatel musí mít účet v doméně serveru. U veřejného webu se obvykle chcete ověřit u poskytovatele členství ASP.NET.

Pokud chcete povolit základní ověřování pomocí služby IIS, nastavte v Web.config projektu ASP.NET režim ověřování na Windows:

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

V tomto režimu služba IIS používá k ověřování přihlašovací údaje systému Windows. Kromě toho musíte povolit základní ověřování ve službě IIS. Ve Správci služby IIS přejděte na Zobrazení funkcí, vyberte Ověřování a povolte základní ověřování.

Obrázek řídicího panelu správce I I S

V projektu webového [Authorize] rozhraní API přidejte atribut pro všechny akce kontroleru, které vyžadují ověření.

Klient se ověřuje sám nastavením autorizační hlavičky v požadavku. Klienti prohlížeče provádějí tento krok automaticky. Klienti, kteří neprojdou, budou muset nastavit hlavičku .

Základní ověřování s vlastním členstvím

Jak už bylo zmíněno, základní ověřování integrované do služby IIS používá přihlašovací údaje Systému Windows. To znamená, že musíte vytvořit účty pro uživatele na hostitelském serveru. U internetových aplikací jsou ale uživatelské účty obvykle uložené v externí databázi.

Následující kód, jak modul HTTP, který provádí základní ověřování. Poskytovatele členství ASP.NET můžete snadno připojit tak, že nahradíte metodu CheckPassword , což je fiktivní metoda v tomto příkladu.

Ve webovém rozhraní API 2 byste měli zvážit vytvoření ověřovacího filtru nebo middlewaru OWIN místo modulu HTTP.

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() 
        {
        }
    }
}

Modul HTTP povolíte tak, že do souboru web.config v části system.webServer přidáte následující kód:

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

Nahraďte "YourAssemblyName" názvem sestavení (bez přípony "dll").

Měli byste zakázat jiná schémata ověřování, jako jsou formuláře nebo ověřování systému Windows.