Authentification de base dans API Web ASP.NET
par Mike Wasson
L’authentification de base est définie dans RFC 2617, Authentification HTTP : Authentification de base et d’accès Digest.
Inconvénients
- Les informations d’identification de l’utilisateur sont envoyées dans la demande.
- Les informations d’identification sont envoyées en texte clair.
- Les informations d’identification sont envoyées à chaque requête.
- Aucun moyen de se déconnecter, sauf en mettant fin à la session du navigateur.
- Vulnérable à la falsification de demandes intersite (CSRF) ; nécessite des mesures anti-CSRF.
Avantages
- Internet standard.
- Pris en charge par tous les principaux navigateurs.
- Protocole relativement simple.
L’authentification de base fonctionne comme suit :
- Si une demande nécessite une authentification, le serveur retourne 401 (non autorisé). La réponse inclut un en-tête WWW-Authenticate, indiquant que le serveur prend en charge l’authentification de base.
- Le client envoie une autre requête, avec les informations d’identification du client dans l’en-tête Autorisation. Les informations d’identification sont mises en forme sous la forme de la chaîne « name:password », encodée en base64. Les informations d’identification ne sont pas chiffrées.
L’authentification de base est effectuée dans le contexte d’un « domaine ». Le serveur inclut le nom du domaine dans l’en-tête WWW-Authenticate. Les informations d’identification de l’utilisateur sont valides dans ce domaine. L’étendue exacte d’un domaine est définie par le serveur. Par exemple, vous pouvez définir plusieurs domaines afin de partitionner les ressources.
Étant donné que les informations d’identification sont envoyées sans chiffrement, l’authentification de base n’est sécurisée que via HTTPS. Consultez Utilisation de SSL dans l’API web.
L’authentification de base est également vulnérable aux attaques CSRF. Une fois que l’utilisateur a entré les informations d’identification, le navigateur les envoie automatiquement sur les demandes suivantes au même domaine, pendant la durée de la session. Cela inclut les demandes AJAX. Consultez Prévention des attaques par falsification de requête intersite (CSRF).
Authentification de base avec IIS
IIS prend en charge l’authentification de base, mais il existe une mise en garde : l’utilisateur est authentifié par rapport à ses informations d’identification Windows. Cela signifie que l’utilisateur doit avoir un compte sur le domaine du serveur. Pour un site web accessible au public, vous souhaitez généralement vous authentifier auprès d’un fournisseur d’appartenance ASP.NET.
Pour activer l’authentification de base à l’aide d’IIS, définissez le mode d’authentification sur « Windows » dans le Web.config de votre projet ASP.NET :
<system.web>
<authentication mode="Windows" />
</system.web>
Dans ce mode, IIS utilise les informations d’identification Windows pour l’authentification. En outre, vous devez activer l’authentification de base dans IIS. Dans le Gestionnaire des SERVICES Internet, accédez à Affichage des fonctionnalités, sélectionnez Authentification et activez l’authentification de base.
Dans votre projet d’API web, ajoutez l’attribut pour toutes les [Authorize]
actions de contrôleur qui nécessitent une authentification.
Un client s’authentifie en définissant l’en-tête Authorization dans la demande. Les clients de navigateur effectuent cette étape automatiquement. Les clients sansrowser devront définir l’en-tête.
Authentification de base avec appartenance personnalisée
Comme mentionné précédemment, l’authentification de base intégrée à IIS utilise les informations d’identification Windows. Cela signifie que vous devez créer des comptes pour vos utilisateurs sur le serveur d’hébergement. Toutefois, pour une application Internet, les comptes d’utilisateur sont généralement stockés dans une base de données externe.
Le code suivant montre comment un module HTTP qui effectue l’authentification de base. Vous pouvez facilement connecter un fournisseur d’appartenance ASP.NET en remplaçant la CheckPassword
méthode, qui est une méthode factice dans cet exemple.
Dans l’API Web 2, vous devez envisager d’écrire un filtre d’authentification ou un intergiciel OWIN, au lieu d’un module 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()
{
}
}
}
Pour activer le module HTTP, ajoutez les éléments suivants à votre fichier web.config dans la section system.webServer :
<system.webServer>
<modules>
<add name="BasicAuthHttpModule"
type="WebHostBasicAuth.Modules.BasicAuthHttpModule, YourAssemblyName"/>
</modules>
Remplacez « YourAssemblyName » par le nom de l’assembly (sans l’extension « dll »).
Vous devez désactiver d’autres schémas d’authentification, tels que Forms ou l’authentification Windows.