Déc

La sécurité, est-ce si important 🚔 ?

Bien sûr !

La sécurité dans les applications est un aspect essentiel du développement logiciel. Elle consiste à protéger les données, les fonctionnalités et les utilisateurs des applications contre les menaces. Elle vise à prévenir des risques tels que :

  • Le vol d’informations sensibles et confidentielles
  • La corruption ou la modification non autorisée des données
  • La perturbation ou l’indisponibilité du service comme DDoS

La sécurité dans les applications est importante pour plusieurs raisons, telles que :

  • Assurer la confiance et la satisfaction des utilisateurs et des clients
  • Protéger la réputation et la crédibilité de l’entreprise ou de l’organisation
  • Éviter les pertes financières ou les sanctions juridiques
  • Respecter les normes et les exigences de qualité

Globalement, la sécurité dans les applications est bien plus qu’une simple mesure technique. Elle joue un rôle fondamental en tant que veilleuse sur les utilisateurs, les données et la réputation de l’entreprise. Imaginez-la comme un bouclier protecteur qui éloigne les menaces, un coffre-fort numérique qui préserve les informations sensibles et une garantie de tranquillité d’esprit pour les utilisateurs.

Mais protection contre quels types de vulnérabilités 🤔 ?

  • Injection de code :

La menace de l’injection de code reste une préoccupation majeure pour les applications ASP.NET, elle demeure la principale vulnérabilité de sécurité des API selon l’OWASP. Imaginons un formulaire de recherche qui génère des résultats en se basant sur ce que l’utilisateur saisit. Si cette entrée n’est pas soumise à une validation rigoureuse côté serveur, une attaque pourrait profiter de cette faille pour insérer un code malveillant.

Le type le plus connu de l’injection de code est l’injection SQL.

Prenons un scénario où une application interroge une base de données en utilisant une entrée fournie par l’utilisateur afin de filtrer les résultats sans une validation appropriée.

string entreeUser = Request.QueryString["username"];

string query = "SELECT * FROM Users WHERE Username = " + entreeUser ;

SqlCommand command = new SqlCommand(query, connection);

 

Dans cet exemple, une attaque peut exploiter le manque de validation d’entrée en fournissant une entrée malveillante, comme “H145DZ6 OR 1=1” donc l’entrée devient SELECT * FROM Users WHERE Username =  H145DZ6 OR 1=1  ce qui altérait la logique de la requête pour toujours renvoyer vrai, exposant potentiellement des données sensibles.

 

Comment se protéger ?

Pour prévenir l’injection SQL, il est crucial d’utiliser des requêtes paramétrées comme l’exemple suivant :

 

string entreeUser = Request.QueryString["username"];

string query = "SELECT * FROM Users WHERE Username = @username";

SqlCommand command = new SqlCommand(query, connection);

command.Parameters.AddWithValue("@username", entreeUser );

 

En utilisant des requêtes paramétrées, l’entrée de l’utilisateur est traitée comme des données plutôt que comme du code exécutable, neutralisant efficacement le risque d’injection SQL.

Une meilleure solution pour prévenir l’injection SQL en .NET est d’utiliser des ORM comme Entity Framework ou Dapper qui rendent le développement plus facile et plus sécurisé.

Prenons Entity Framework comme exemple, en utilisant LINQ pour les opérations CRUD :

_dataContext.Books.Where(b => b.Title.Contains(“titre”)).ToList();

 

Lorsque Entity Framework traduira cette requête LINQ en SQL, il rend “Title” comme un paramètre :

SELECT * FROM Books WHERE Title = @param

 

Pour les cas de Dapper, on peut aussi utiliser des requêtes paramétrées :

var query = "SELECT * FROM Books WHERE Title LIKE @SearchTerm";

var data = connection.Query<Book>(query, new { SearchTerm = “titre” }).ToList();

 

  • Cross-site scripting (XSS):

Les attaques de type Cross-Site Scripting, également appelées attaques XSS, sont une autre forme d’attaque par injection qui insère un code malveillant dans des sites Web. L’attaque exploite une faille dans une application Web cible pour envoyer un type de code malveillant, le plus souvent du JavaScript côté client, à un utilisateur final. Plutôt que de cibler directement le serveur d’application, les attaques XSS visent généralement les utilisateurs de l’application. Les organisations et les entreprises exécutant des applications Web peuvent ouvrir la voie aux attaques XSS s’ils affichent du contenu provenant d’utilisateurs comme les commentaires ou de sources non fiables sans échappement ou validation adéquate.

Prenons par exemple les commentaires qui se trouvent dans un blog, un attaquant peut insérer le commentaire suivant :

<script>alert('Commentaire Malveillant');</script>

 

Ce commentaire sera rendu sur la page tel quel, provoquant l’exécution du script malveillant par les navigateurs des autres utilisateurs et déclenchant une boîte d’alerte avec le message « Commentaire Malveillant », un attaquant peut utiliser cette méthode pour voler les cookies des sessions des autres utilisateurs.

Afin de protéger contre ce type d’attaques, il faut encoder correctement le contenu généré par les utilisateurs avant de le rendre sur la page, en utilisant des contrôles en ASP.NET Razor pages comme  « `HttpUtility.HtmlEncode« `, par conséquent le commentaire sera traité comme un texte et non pas un script.

 

  • Cross-site forgery (CSRF) :

Une attaque par Cross-Site Request Forgery, appelée attaque CSRF, induit un utilisateur authentifié à exécuter des actions involontaires en envoyant des requêtes malveillantes sans qu’il en ait conscience.

En général, lorsqu’une fonctionnalité est vulnérable aux attaques CSRF, les attaques cherchent à tromper les utilisateurs en chargeant une page malveillante.

Cette page contenant du code malveillant enverra des requêtes à travers le navigateur de l’utilisateur comme s’il s’agissait d’une action légitime de l’utilisateur, permettant à l’attaquant d’effectuer des actions telles que la modification du mot de passe et/ou d’autres informations personnelles, ou encore l’exécution des actions sans que l’utilisateur ne les connaisse.

Pour bien comprendre ce type d’attaques, supposons qu’il existe un site Web sur lequel les utilisateurs peuvent modifier leur adresse e-mail en soumettant un formulaire avec le code HTML suivant :

<form action="https://example.com/change-email" method="POST">

<input type="email" name="new_email" placeholder="New Email">

<button type="submit">Change Email</button>

</form>

 

Ce formulaire permet aux utilisateurs de modifier leur adresse e-mail en soumettant une requête POST à https://example.com/change-email avec la nouvelle adresse e-mail. Lorsqu’un utilisateur est connecté et soumet ce formulaire, son adresse e-mail est mise à jour.

Cette application utilise simplement des cookies de session pour vérifier les demandes. De plus, les cookies de session n’ont pas l’attribut SameSite.

Imaginez maintenant qu’un attaquant créé un site Web malveillant avec le code HTML suivant :

<html>

<head>

<title>site Web malveillant</title>

</head>

<body>

<h1>Cliquez sur le bouton pour gagner un cadeau !</h1>

<form action="https://example.com/change-email" method="POST">

<input type="email" name="new_email" value="attacker@example.com">

<button type="submit">Cliquez ici !</button>

</form>

</body>

</html>

 

Dans cet exemple, le site web inclut un formulaire caché qui imite le formulaire légitime de https://example.com/change-email. L’utilisateur est trompé en cliquant sur le bouton « Cliquez ici ! » sur le site web de l’attaquant. Ce bouton déclenche une requête POST vers https://example.com/change-email avec la nouvelle adresse e-mail définie par l’adresse e-mail de l’attaquant (attacker@example.com).

Étant donné que l’utilisateur est déjà authentifié sur https://example.com, le site web traite la requête POST comme si elle était légitime et modifie l’adresse e-mail de l’utilisateur pour qu’elle corresponde à l’adresse e-mail de l’attaquant, le tout sans le consentement de l’utilisateur. C’est ce qu’on appelle une attaque CSRF.

Voilà ! Maintenant on a donné la main à l’attaquant pour utiliser son propre email, la même chose peut être faite avec les mots de passe.

 

Comment se protéger contre cette attaque ?

Il est important en tant qu’utilisateur de ne jamais cliquer sur des liens inconnus et de toujours s’assurer que le lien est correct et qu’il s’agit d’une page officielle de site web. 

Concernant la sécurité côté serveur, la première raison ayant rendu possible l’attaque est la non-utilisation de l’attribut SameSite pour les cookies. L’accès aux cookies de session de la page officielle était ainsi possible, même depuis une autre page non légitime. En ASP.NET, il suffit d’ajouter cet attribut :

var cookieOptions = new CookieOptions

{

                SameSite = SameSiteMode.Strict

};

 

Une deuxième raison est que l’application s’appuie uniquement sur les cookies de session pour changer l’email ou le mot de passe, l’application n’effectue pas de vérification adéquate pour identifier un utilisateur, par exemple en utilisant un email ou SMS de confirmation. On peut utiliser des méthodes prédéfinies dans ASP.NET Identity pour envoyer un email de confirmation, par exemple :

var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);

var confirmationLink = Url.Action(nameof(ConfirmEmailChange), "Account", new { token, email = user.Email }, Request.Scheme);

var message = new Message(new string[] { user.Email }, "Confirmation email link", confirmationLink, null);

await _emailSender.SendEmailAsync(message);

 

  • Gestion incorrecte des erreurs :

La gestion incorrecte des erreurs est une faille de sécurité qui peut compromettre la confidentialité, l’intégrité et la disponibilité des applications. Elle se produit lorsque nous ne traitons pas correctement les exceptions ou les erreurs qui surviennent pendant l’exécution du code. 

Par exemple, si une erreur affiche des informations sensibles sur l’écran de l’utilisateur, comme le mot de passe, une clé secrète (token) ou le chemin du fichier, une attaque peut les exploiter pour accéder au système ou aux données. De même, si une erreur provoque un arrêt ou un ralentissement de l’application, il est possible d’en profiter pour lancer une attaque par déni de service (DDOS). Une autre manière d’afficher des données sensibles est par l’activation des messages de débogage dans l’environnement de production. Pour éviter ces risques, il est important de suivre les bonnes pratiques de gestion des erreurs. Voici quelques méthodes pour bien sécuriser votre application en .NET :

  • Utiliser les messages de débogage seulement dans un environnement de test ou développement :

if (app.Environment.IsDevelopment())

{

    app.UseExceptionHandler();

/* Afin de voir les messages d’exception seulement dans l’environnement de développement *

}

 

  • Utiliser des middlewares pour renvoyer un message personnalisé en cas d’erreur vers le client : 

ErrorHandlingMiddleware.cs

 

public class ErrorHandlingMiddleware

{

private readonly RequestDelegate _next;

public ErrorHandlingMiddleware(RequestDelegate next)

{

_next = next;

}

public async Task Invoke(HttpContext context)

{

try

{

      await _next(context);

}

      catch (Exception ex)

{

  await HandleGlobalExceptionAsync(context, ex);

}

}

       

  private Task HandleGlobalExceptionAsync(HttpContext context, Exception ex)

{

      var problemDetails = new

        {

Type = Enum.GetName(HttpStatusCode.InternalServerError)

Title = "An unexpected error occured, Please try again later.",

Title = ex.Message,

Instance = context.Request.Path,

Status = (int)HttpStatusCode.InternalServerError

Status = (int)HttpStatusCode.InternalServerError

};

   var settings = new JsonSerializerSettings();

   settings.NullValueHandling = NullValueHandling.Ignore;

   var result = JsonConvert.SerializeObject(problemDetails, settings);

        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

              context.Response.ContentType = "application/json";

                      return context.Response.WriteAsync(result);

     }

  }

 

 

Program.cs

 

app.UseMiddleware<ErrorHandlingMiddleware>();

 

Utilisez toujours des blocs try-catch:

[HttpGet]

public IActionResult UneAction()

{

try

{

            // Un code qui peut lever une exception 

  int resultat = FaireUneOperation();

  return Ok(resultat);

  }

  catch (Exception ex)

  {

  Log.Error(ex, "Une exception levée en FaireUneOperation.");

 

      // Intercepter l’exception et envoyer un erreur au client

 return StatusCode(StatusCodes.Status500InternalServerError, "Une erreur est survenue.");

   }

}

          

 

Je suis protégé contre ces vulnérabilités, comment renforcer la sécurité de mon application ?

  • Utilisation de la sécurité basée sur les rôles :

Pour que votre application ne soit accessible qu’à un personnel sélectionné, on peut ajouter l’attribut ‘[Authorize(Roles = « role1,role2… »)]’ soit au niveau de contrôleur ou au niveau de la méthode :

[Authorize(Roles = "Administrateur")]

public class AdministrationController : ControllerBase

{

public IActionResult Admin() => Ok("Administrateur");

 }

Ou 

[Authorize(Roles = "Administrateur")]

public IActionResult Admin() => Ok("Administrateur");


  • Cryptage des données :

Une des choses importantes est de bien crypter les données sensibles comme les mots de passe ou les données personnelles. .NET nous offre des méthodes pour le cryptage.

Pour stocker les mots de passe, on doit faire un hashing pour ne pas les sauvegarder en texte clair. ASP.NET Identity nous fournit l’interface IPasswordHasher qui contient les méthodes de hashing et de vérification de hash :

public interface IPasswordHasher<TUser> where TUser : class

{

    string HashPassword(TUser user, string password);

     PasswordVerificationResult VerifyHashedPassword(

     TUser user, string hashedPassword, string providedPassword);

}

 

NOTE : On ne doit pas crypter toutes les données car il y a toujours un coût. Par nature, c’est lent et intensif en termes de traitement car c’est cela qui vous procure réellement la sécurité, crypter seulement des données comme les mots de passe ou les données des cartes bancaires.

  • Sécurité du réseau et des communications :

La sécurité des applications peut inclure du matériel ou des logiciels qui identifient ou minimisent les vulnérabilités en matière de sécurité. Un routeur qui empêche quiconque de visualiser l’adresse IP d’un ordinateur depuis Internet est une forme de sécurité des applications matérielle. Cependant, les mesures de sécurité au niveau de l’application sont généralement également intégrées au logiciel, tel qu’un pare-feu d’application qui définit strictement quelles activités sont autorisées et interdites.

  • Tests de sécurité :

Les tests de sécurité, souvent appelés évaluations de sécurité ou tests de pénétration, sont un élément essentiel de toute stratégie de cybersécurité solide. Ces tests impliquent une évaluation systématique des systèmes d’information et des réseaux d’une organisation afin d’identifier les vulnérabilités et les faiblesses qui pourraient être exploitées par des acteurs malveillants. Ils englobent toute une gamme de techniques, de la numérisation des vulnérabilités au piratage éthique, afin de simuler des menaces cyber réelles. En effectuant régulièrement des tests de sécurité, les organisations peuvent identifier et traiter de manière proactive les risques potentiels pour renforcer leurs défenses et garantir la confidentialité, l’intégrité et la disponibilité de leurs données et systèmes.

Quelques bonnes pratiques pour un développement bien sécurisé pour les applications .NET :

  • Utilisation de frameworks comme ASP.NET Identity ou des services d’identités comme Microsoft Intra (Azure Active Directory), Auth0
  • Validation des entrées utilisateur en vérifiant et validant rigoureusement les données fournies par les utilisateurs pour éviter toute injection de code malveillant ou des données incorrectes dans les systèmes.
  • Mise à jour régulière des composants en maintenant et en mettant fréquemment à jour les composants logiciels et matériels afin de s’assurer qu’ils sont sécurisés contre les vulnérabilités connues et les failles de sécurité.

 

Yassine CHAHID

Related Posts

Leave A Comment