Condividi tramite


Autenticazione di base in API Web ASP.NET

di Mike Wasson

L'autenticazione di base è definita in RFC 2617, autenticazione HTTP: Autenticazione di base e digest.

Svantaggi

  • Le credenziali utente vengono inviate nella richiesta.
  • Le credenziali vengono inviate come testo non crittografato.
  • Le credenziali vengono inviate con ogni richiesta.
  • Nessun modo per disconnettersi, tranne terminando la sessione del browser.
  • Vulnerabile alla richiesta cross-site forgery (CSRF); richiede misure anti-CSRF.

Vantaggi

  • Internet standard.
  • Supportato da tutti i principali browser.
  • Protocollo relativamente semplice.

L'autenticazione di base funziona come indicato di seguito:

  1. Se una richiesta richiede l'autenticazione, il server restituisce 401 (non autorizzato). La risposta include un'intestazione WWW-Authenticate, che indica che il server supporta l'autenticazione di base.
  2. Il client invia un'altra richiesta, con le credenziali client nell'intestazione Di autorizzazione. Le credenziali vengono formattate come stringa "name:password", con codifica base64. Le credenziali non vengono crittografate.

L'autenticazione di base viene eseguita nel contesto di un 'area di autenticazione'. Il server include il nome dell'area di autenticazione nell'intestazione WWW-Authenticate. Le credenziali dell'utente sono valide all'interno dell'area di autenticazione. L'ambito esatto di un'area di autenticazione è definito dal server. Ad esempio, è possibile definire più aree di autenticazione per partizionare le risorse.

Diagramma dell'autenticazione di base

Poiché le credenziali vengono inviate non crittografate, l'autenticazione di base è sicura solo tramite HTTPS. Vedere Uso di SSL nell'API Web.

L'autenticazione di base è anche vulnerabile agli attacchi CSRF. Dopo aver immesso le credenziali, il browser li invia automaticamente alle richieste successive allo stesso dominio, per la durata della sessione. Sono incluse le richieste AJAX. Vedere Prevenzione degli attacchi della richiesta tra siti (CSRF).

Autenticazione di base con IIS

IIS supporta l'autenticazione di base, ma esiste un'attenzione: l'utente viene autenticato con le credenziali di Windows. Ciò significa che l'utente deve avere un account nel dominio del server. Per un sito Web pubblico, in genere si vuole eseguire l'autenticazione con un provider di appartenenza ASP.NET.

Per abilitare l'autenticazione di base tramite IIS, impostare la modalità di autenticazione su "Windows" nella Web.config del progetto di ASP.NET:

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

In questa modalità IIS usa le credenziali di Windows per l'autenticazione. È inoltre necessario abilitare l'autenticazione di base in IIS. In Gestione IIS passare a Visualizzazione funzionalità, selezionare Autenticazione e abilitare l'autenticazione di base.

Immagine del dashboard di I S Manager

Nel progetto API Web aggiungere l'attributo per tutte le azioni del controller necessarie per l'autenticazione [Authorize] .

Un client esegue l'autenticazione impostando l'intestazione Di autorizzazione nella richiesta. I client del browser eseguono automaticamente questo passaggio. I client nonbrowser dovranno impostare l'intestazione.

Autenticazione di base con appartenenza personalizzata

Come accennato, l'autenticazione di base incorporata in IIS usa le credenziali di Windows. Ciò significa che è necessario creare account per gli utenti nel server di hosting. Tuttavia, per un'applicazione Internet, gli account utente vengono in genere archiviati in un database esterno.

Il codice seguente illustra come un modulo HTTP che esegue l'autenticazione di base. È possibile collegare facilmente un provider di appartenenza ASP.NET sostituendo il CheckPassword metodo, ovvero un metodo fittizio in questo esempio.

Nell'API Web 2 è consigliabile scrivere un filtro di autenticazione o un middleware OWIN anziché un modulo 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() 
        {
        }
    }
}

Per abilitare il modulo HTTP, aggiungere quanto segue al file di web.config nella sezione system.webServer :

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

Sostituire "YourAssemblyName" con il nome dell'assembly (non inclusa l'estensione "dll").

È consigliabile disabilitare altri schemi di autenticazione, ad esempio Form o Autenticazione di Windows.