Authentification et autorisation avancées

Guide complet sur Authentification et autorisation avancées : techniques avancées, conseils d'experts et mise en pratique.

Olivier Dupuy
21 juillet 2025

11

Vues

0

Commentaires

3

Min de lecture

Sécurité applicative

La sécurité est un aspect fondamental du développement d'applications. Cet article traite de Authentification et autorisation avancées et des meilleures pratiques pour sécuriser vos applications ASP.NET Core.

Authentification et autorisation

Configuration de l'authentification JWT

// Configuration dans Program.cs
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"]))
        };
    });

// Service de génération de tokens
public class TokenService
{
    private readonly IConfiguration _config;
    
    public TokenService(IConfiguration config)
    {
        _config = config;
    }
    
    public string GenerateToken(ApplicationUser user, IList<string> roles)
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_config["Jwt:SecretKey"]);
        
        var claims = new List<Claim>
        {
            new(ClaimTypes.NameIdentifier, user.Id),
            new(ClaimTypes.Name, user.UserName),
            new(ClaimTypes.Email, user.Email)
        };
        
        // Ajouter les rôles
        claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
        
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims),
            Expires = DateTime.UtcNow.AddHours(24),
            SigningCredentials = new SigningCredentials(
                new SymmetricSecurityKey(key), 
                SecurityAlgorithms.HmacSha256Signature),
            Issuer = _config["Jwt:Issuer"],
            Audience = _config["Jwt:Audience"]
        };
        
        var token = tokenHandler.CreateToken(tokenDescriptor);
        return tokenHandler.WriteToken(token);
    }
}

Autorisation basée sur les politiques

// Configuration des politiques
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy => 
        policy.RequireRole("Admin"));
        
    options.AddPolicy("AuthorOrAdmin", policy => 
        policy.RequireRole("Author", "Admin"));
        
    options.AddPolicy("MinimumAge", policy => 
        policy.RequireClaim("birthdate", birthdate => 
            DateTime.Today.Year - DateTime.Parse(birthdate).Year >= 18));
            
    // Autorisation basée sur les ressources
    options.AddPolicy("OwnerPolicy", policy =>
        policy.Requirements.Add(new OwnerRequirement()));
});

// Handler personnalisé pour l'autorisation
public class OwnerAuthorizationHandler : AuthorizationHandler<OwnerRequirement, Article>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        OwnerRequirement requirement,
        Article resource)
    {
        var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        
        if (userId == resource.AuthorId || context.User.IsInRole("Admin"))
        {
            context.Succeed(requirement);
        }
        
        return Task.CompletedTask;
    }
}

Protection contre les attaques

Validation et sanitisation des données

// Modèle avec validation
public class SecureArticleDto
{
    [Required]
    [StringLength(200, MinimumLength = 5)]
    [RegularExpression(@"^[a-zA-ZÀ-ÿ0-9\s\-_]+$", 
        ErrorMessage = "Le titre contient des caractères non autorisés")]
    public string Title { get; set; }
    
    [Required]
    [StringLength(5000)]
    public string Content { get; set; }
    
    [EmailAddress]
    public string? AuthorEmail { get; set; }
    
    [Range(1, int.MaxValue, ErrorMessage = "ID de catégorie invalide")]
    public int CategoryId { get; set; }
}

// Service de sanitisation
public class InputSanitizer
{
    private readonly HtmlSanitizer _sanitizer;
    
    public InputSanitizer()
    {
        _sanitizer = new HtmlSanitizer();
        _sanitizer.AllowedTags.Clear();
        _sanitizer.AllowedTags.Add("p");
        _sanitizer.AllowedTags.Add("br");
        _sanitizer.AllowedTags.Add("strong");
        _sanitizer.AllowedTags.Add("em");
        _sanitizer.AllowedTags.Add("ul");
        _sanitizer.AllowedTags.Add("ol");
        _sanitizer.AllowedTags.Add("li");
    }
    
    public string SanitizeHtml(string input)
    {
        if (string.IsNullOrEmpty(input))
            return string.Empty;
            
        return _sanitizer.Sanitize(input);
    }
    
    public string EscapeForSql(string input)
    {
        return input?.Replace("'", "''") ?? string.Empty;
    }
}

Protection CSRF et en-têtes de sécurité

// Configuration des en-têtes de sécurité
app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
    context.Response.Headers.Add("X-Frame-Options", "DENY");
    context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
    context.Response.Headers.Add("Referrer-Policy", "strict-origin-when-cross-origin");
    context.Response.Headers.Add("Content-Security-Policy", 
        "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'");
    
    await next();
});

// Protection CSRF
builder.Services.AddAntiforgery(options =>
{
    options.HeaderName = "X-CSRF-TOKEN";
    options.Cookie.Name = "__Secure-CSRF-Token";
    options.Cookie.HttpOnly = true;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateArticle([FromBody] SecureArticleDto model)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);
        
    // Traitement sécurisé...
    return Ok();
}

Gestion sécurisée des données sensibles

// Service de chiffrement
public class EncryptionService
{
    private readonly string _encryptionKey;
    
    public EncryptionService(IConfiguration config)
    {
        _encryptionKey = config["Encryption:Key"];
    }
    
    public string Encrypt(string plainText)
    {
        using var aes = Aes.Create();
        aes.Key = Convert.FromBase64String(_encryptionKey);
        aes.GenerateIV();
        
        using var encryptor = aes.CreateEncryptor();
        using var ms = new MemoryStream();
        using var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
        using var writer = new StreamWriter(cs);
        
        writer.Write(plainText);
        writer.Close();
        
        var encrypted = ms.ToArray();
        var result = new byte[aes.IV.Length + encrypted.Length];
        Array.Copy(aes.IV, 0, result, 0, aes.IV.Length);
        Array.Copy(encrypted, 0, result, aes.IV.Length, encrypted.Length);
        
        return Convert.ToBase64String(result);
    }
    
    public string Decrypt(string cipherText)
    {
        var buffer = Convert.FromBase64String(cipherText);
        
        using var aes = Aes.Create();
        aes.Key = Convert.FromBase64String(_encryptionKey);
        
        var iv = new byte[aes.IV.Length];
        var encrypted = new byte[buffer.Length - iv.Length];
        
        Array.Copy(buffer, 0, iv, 0, iv.Length);
        Array.Copy(buffer, iv.Length, encrypted, 0, encrypted.Length);
        
        aes.IV = iv;
        
        using var decryptor = aes.CreateDecryptor();
        using var ms = new MemoryStream(encrypted);
        using var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
        using var reader = new StreamReader(cs);
        
        return reader.ReadToEnd();
    }
}

Audit et logging sécurisé

// Service d'audit
public class SecurityAuditService
{
    private readonly ILogger<SecurityAuditService> _logger;
    
    public SecurityAuditService(ILogger<SecurityAuditService> logger)
    {
        _logger = logger;
    }
    
    public void LogSecurityEvent(string userId, string action, string resource, bool success)
    {
        _logger.LogWarning("Security Event: User {UserId} attempted {Action} on {Resource}. Success: {Success}",
            userId, action, resource, success);
    }
    
    public void LogSuspiciousActivity(string ipAddress, string userAgent, string details)
    {
        _logger.LogCritical("Suspicious Activity: IP {IP}, UserAgent {UserAgent}, Details: {Details}",
            ipAddress, userAgent, details);
    }
}

Conclusion

La sécurité avec Authentification et autorisation avancées doit être intégrée dès la conception. Les mesures présentées - authentification robuste, autorisation granulaire, protection contre les attaques et audit - constituent les fondamentaux d'une application sécurisée. Restez vigilant et mettez régulièrement à jour vos connaissances en sécurité.

Partager cet article
42
12

Commentaires (0)

Rejoignez la discussion

Connectez-vous pour partager votre avis et échanger avec la communauté

Première discussion

Soyez le premier à partager votre avis sur cet article !

À propos de l'auteur
Olivier Dupuy

Développeur passionné et créateur de contenu technique. Expert en développement web moderne avec ASP.NET Core, JavaScript, et technologies cloud.

Profil
Articles similaires
API versioning strategies
02 août 2025 0
C# & .NET
Cryptographie post-quantique
02 août 2025 0
C# & .NET
Géolocalisation et cartes interactives
02 août 2025 0
C# & .NET
Navigation rapide
Commentaires (0)