Uwierzytelnianie podstawowe w internetowym interfejsie API ASP.NET
Autor: Mike Wasson
Uwierzytelnianie podstawowe jest definiowane w dokumencie RFC 2617, uwierzytelnianie HTTP: uwierzytelnianie podstawowe i szyfrowane.
Wady
- Poświadczenia użytkownika są wysyłane w żądaniu.
- Poświadczenia są wysyłane jako zwykły tekst.
- Poświadczenia są wysyłane z każdym żądaniem.
- Nie ma możliwości wylogowania się, z wyjątkiem zakończenia sesji przeglądarki.
- Podatne na fałszerzowania żądań między witrynami (CSRF); wymaga środków anty-CSRF.
Zalety
- Standard internetowy.
- Obsługiwane przez wszystkie główne przeglądarki.
- Stosunkowo prosty protokół.
Uwierzytelnianie podstawowe działa w następujący sposób:
- Jeśli żądanie wymaga uwierzytelnienia, serwer zwraca błąd 401 (Brak autoryzacji). Odpowiedź zawiera nagłówek WWW-Authenticate wskazujący, że serwer obsługuje uwierzytelnianie podstawowe.
- Klient wysyła kolejne żądanie z poświadczeniami klienta w nagłówku Autoryzacja. Poświadczenia są formatowane jako ciąg "name:password", zakodowany w formacie Base64. Poświadczenia nie są szyfrowane.
Uwierzytelnianie podstawowe jest wykonywane w kontekście "obszaru". Serwer zawiera nazwę obszaru w nagłówku WWW-Authenticate. Poświadczenia użytkownika są prawidłowe w tym obszarze. Dokładny zakres obszaru jest definiowany przez serwer. Można na przykład zdefiniować kilka obszaru w celu partycjonowania zasobów.
Ponieważ poświadczenia są wysyłane niezaszyfrowane, uwierzytelnianie podstawowe jest bezpieczne tylko za pośrednictwem protokołu HTTPS. Zobacz Praca z protokołem SSL w internetowym interfejsie API.
Uwierzytelnianie podstawowe jest również narażone na ataki CSRF. Po wprowadzeniu poświadczeń przez użytkownika przeglądarka automatycznie wysyła je do kolejnych żądań do tej samej domeny przez cały czas trwania sesji. Obejmuje to żądania AJAX. Zobacz Zapobieganie atakom polegającym na fałszerzowaniu żądań między witrynami (CSRF).
Uwierzytelnianie podstawowe za pomocą usług IIS
Usługi IIS obsługują uwierzytelnianie podstawowe, ale istnieje zastrzeżenie: użytkownik jest uwierzytelniany przy użyciu poświadczeń systemu Windows. Oznacza to, że użytkownik musi mieć konto w domenie serwera. W przypadku publicznej witryny sieci Web zazwyczaj chcesz uwierzytelnić się u dostawcy członkostwa ASP.NET.
Aby włączyć uwierzytelnianie podstawowe przy użyciu usług IIS, ustaw tryb uwierzytelniania na "Windows" w Web.config projektu ASP.NET:
<system.web>
<authentication mode="Windows" />
</system.web>
W tym trybie usługi IIS używają poświadczeń systemu Windows do uwierzytelniania. Ponadto należy włączyć uwierzytelnianie podstawowe w usługach IIS. W Menedżerze usług IIS przejdź do pozycji Widok funkcji, wybierz pozycję Uwierzytelnianie i włącz uwierzytelnianie podstawowe.
W projekcie internetowego interfejsu [Authorize]
API dodaj atrybut dla wszystkich akcji kontrolera, które wymagają uwierzytelniania.
Klient uwierzytelnia się sam, ustawiając nagłówek autoryzacji w żądaniu. Klienci przeglądarki wykonują ten krok automatycznie. Klienci niebędącybrowser muszą ustawić nagłówek.
Uwierzytelnianie podstawowe z członkostwem niestandardowym
Jak wspomniano, uwierzytelnianie podstawowe wbudowane w usługi IIS używa poświadczeń systemu Windows. Oznacza to, że musisz utworzyć konta dla użytkowników na serwerze hostingu. Jednak w przypadku aplikacji internetowej konta użytkowników są zwykle przechowywane w zewnętrznej bazie danych.
Poniższy kod przedstawiający sposób wykonywania uwierzytelniania podstawowego przez moduł HTTP. Możesz łatwo podłączyć dostawcę członkostwa ASP.NET, zastępując CheckPassword
metodę , która jest fikcyjną metodą w tym przykładzie.
W internetowym interfejsie API 2 należy rozważyć napisanie filtru uwierzytelniania lub oprogramowania pośredniczącego OWIN zamiast modułu 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()
{
}
}
}
Aby włączyć moduł HTTP, dodaj następujący kod do pliku web.config w sekcji system.webServer :
<system.webServer>
<modules>
<add name="BasicAuthHttpModule"
type="WebHostBasicAuth.Modules.BasicAuthHttpModule, YourAssemblyName"/>
</modules>
Zastąp ciąg "YourAssemblyName" nazwą zestawu (bez rozszerzenia "dll").
Należy wyłączyć inne schematy uwierzytelniania, takie jak formularze lub uwierzytelnianie systemu Windows.