DTeK Learn logo

Angular et la sécurité : Comment ça fonctionne ?

06/09/2023

Explorons les aspects de la sécurité dans Angular et comment les maîtriser pour protéger efficacement ton application. Nous aborderons plusieurs exemples de code, cas concrets, failles de sécurité courantes et les solutions pour les prévenir, tout en se concentrant sur l’injection de code.

jeune développeur en reconversion professionnelle sur son ordinateur à son bureau

1. Comprendre les bases de la sécurité dans Angular

1.1 XSS et Injection de code

L’injection de code, notamment le Cross-Site Scripting (XSS), est une vulnérabilité de sécurité qui permet à un attaquant d’injecter du code malveillant dans une application Web. Il existe trois principaux types de XSS :

  1. Reflected XSS : Le code malveillant provient de la requête de l’utilisateur et est reflété dans la réponse HTTP sans être stocké.
  2. Stored XSS : Le code malveillant est stocké dans la base de données ou le système de fichiers de l’application et est renvoyé à chaque fois qu’un utilisateur accède à la page concernée.
  3. DOM-based XSS : Le code malveillant est exécuté dans le Document Object Model (DOM) de la page, sans modifier le code source de la page elle-même.

Exemple de Reflected XSS : Un attaquant pourrait envoyer un lien contenant du code JavaScript malveillant dans une chaîne de requête, qui serait ensuite interprété et exécuté par le navigateur de la victime :

https://exemple.com/recherche?term=<script>alert(‘XSS’)</script>

1.2 Sanitization et le DomSanitizer

Angular prévient automatiquement de nombreuses injections de code en appliquant des mesures de sécurité telles que l’encodage des caractères spéciaux lors de l’interpolation des données. Cependant, dans certains cas, il est nécessaire d’utiliser le service DomSanitizer pour désinfecter et sécuriser les données.

Exemple d’utilisation du DomSanitizer : Si tu souhaites intégrer du contenu HTML potentiellement dangereux provenant d’une source externe, tu peux utiliser DomSanitizer pour le désinfecter avant de l’ajouter au DOM :

import { DomSanitizer, SafeHtml } from ‘@angular/platform-browser’;

constructor(private sanitizer: DomSanitizer) {}

sanitizeHtml(unsafeHtml: string): SafeHtml {
    return this.sanitizer.bypassSecurityTrustHtml(unsafeHtml);
}

1.3 Content Security Policy (CSP)

La Content Security Policy (CSP) est un mécanisme de sécurité qui permet de définir un ensemble de règles pour contrôler les ressources chargées par une application Web. Une politique CSP efficace peut empêcher les attaques XSS en restreignant l’exécution de scripts inline et en limitant les sources de contenu.

Exemple de CSP : Voici un exemple de CSP qui interdit l’exécution de scripts inline et ne permet de charger des scripts que depuis le domaine de l’application :

Content-Security-Policy: default-src ‘self’; script-src ‘self’; img-src ‘self’;

Pour utiliser cette CSP avec Angular, ajoute-la à l’en-tête HTTP de la réponse dans la configuration de ton serveur Web.

2. Exemples de code

2.1 Utilisation du DomSanitizer pour prévenir les injections de code

Si tu souhaites afficher du contenu HTML dynamique provenant d’une source externe, tu peux utiliser le DomSanitizer pour le désinfecter avant de l’ajouter au DOM.

import { Component } from ‘@angular/core’;

import { DomSanitizer, SafeHtml } from ‘@angular/platform-browser’;

@Component({
    selector: ‘app-root’,
    template: `<div [innerHtml]= »sanitizedHtml »></div>`,
})

export class AppComponent {
    sanitizedHtml: SafeHtml;
    constructor(private sanitizer: DomSanitizer) {
        const unsafeHtml = ‘<div onclick= »alert(\’XSS\’) »>Cliquez-moi</div>’;
        this.sanitizedHtml = this.sanitizeHtml(unsafeHtml);
    }
    sanitizeHtml(unsafeHtml: string): SafeHtml {
        return this.sanitizer.bypassSecurityTrustHtml(unsafeHtml);
    }
}

Dans cet exemple, nous utilisons DomSanitizer pour désinfecter le contenu HTML potentiellement dangereux avant de l’insérer dans le DOM à l’aide de la propriété innerHtml.

2.2 Implémentation d’une stratégie CSP dans Angular

Pour implémenter une stratégie CSP dans Angular, tu dois ajouter des règles spécifiques à ton application. Voici un exemple de CSP pour une application Angular:

Content-Security-Policy: default-src ‘self’; script-src ‘self’; img-src ‘self’; style-src ‘self’ ‘unsafe-inline’; font-src ‘self’ data:; connect-src ‘self’ https://your-api-domain.com;

Cette CSP autorise uniquement les ressources provenant du domaine de l’application (y compris les styles inline), les polices au format data, et les connexions API vers ton domaine spécifique.

Pour ajouter cette CSP à ton application, tu dois configurer ton serveur Web pour inclure l’en-tête Content-Security-Policy dans les réponses HTTP. Voici comment le faire avec un serveur Express :

const express = require(‘express’);

const app = express();

const csp = « default-src ‘self’; script-src ‘self’; img-src ‘self’; style-src ‘self’ ‘unsafe-inline’; font-src ‘self’ data:; connect-src ‘self’ https://your-api-domain.com; »;

app.use((req, res, next) => {
    res.setHeader(‘Content-Security-Policy’, csp);
    next();
});

app.use(express.static(‘./dist/your-app’));

app.listen(3000, () => console.log(‘Listening on port 3000’));

2.3 Sécurisation des appels API avec HttpClient et HttpHeaders

Pour sécuriser les appels API dans Angular, utilise HttpClient et HttpHeaders pour ajouter des en-têtes d’autorisation ou d’autres en-têtes de sécurité aux requêtes.

import { Injectable } from ‘@angular/core’;

import { HttpClient, HttpHeaders } from ‘@angular/common/http’;

@Injectable({
    providedIn: ‘root’
})

export class ApiService {
    private apiUrl = ‘https://your-api-domain.com’;
    constructor(private http: HttpClient) {}
    getSecureData() {
        const headers = new HttpHeaders().set(‘Authorization’, ‘Bearer your-token’);
        return this.http.get(`${this.apiUrl}/secure-data`, { headers });
    }
}

Dans cet exemple, nous utilisons HttpHeaders pour ajouter un en-tête d’autorisation avec un token Bearer aux requêtes API. Cela garantit que seuls les utilisateurs authentifiés peuvent accéder aux données sécurisées.

2.4 Utilisation des intercepteurs pour sécuriser les appels API

Les intercepteurs HttpClient sont un autre moyen de sécuriser les appels API dans Angular. Ils permettent de gérer les requêtes et les réponses HTTP de manière centralisée, ce qui est particulièrement utile pour ajouter des en-têtes d’authentification à toutes les requêtes sortantes.

import { Injectable } from ‘@angular/core’;

import { HttpInterceptor, HttpRequest, HttpHandler, HttpHeaders } from ‘@angular/common/http’;

@Injectable()

export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
const authToken = ‘your-token’;
const authReq = req.clone({
headers: new HttpHeaders().set(‘Authorization’, `Bearer ${authToken}`)
});
return next.handle(authReq);
}
}

Pour utiliser cet intercepteur, ajoute-le au tableau des providers dans AppModule:

import { HttpClientModule, HTTP_INTERCEPTORS } from ‘@angular/common/http’;

import { AuthInterceptor } from ‘./auth.interceptor’;

@NgModule({
imports: [BrowserModule, HttpClientModule],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
],
bootstrap: [AppComponent],
})

export class AppModule {}

Maintenant, l’intercepteur ajoutera automatiquement l’en-tête d’autorisation à toutes les requêtes HttpClient, ce qui permet de sécuriser les appels API de manière centralisée.

3. Cas concrets et exemples de failles​

3.1 Exemple de faille XSS

Dans un forum en ligne, les utilisateurs peuvent publier des messages contenant du texte et des liens. Un attaquant crée un message contenant le code JavaScript suivant :

<a href= »javascript:alert(‘XSS’) »>Clique ici pour voir les images</a>

Lorsqu’un utilisateur clique sur ce lien, le code JavaScript malveillant s’exécute dans son navigateur, permettant à l’attaquant d’accéder aux données sensibles de l’utilisateur ou de prendre le contrôle de son compte.

Pour prévenir cette faille, Angular encode automatiquement les caractères spéciaux lors de l’interpolation des données. Toutefois, si tu dois inclure du contenu HTML dynamique, utilise le DomSanitizer pour désinfecter le contenu avant de l’ajouter au DOM (comme expliqué dans la section 2.1).

3.2 Vulnérabilité lors de l’interpolation de données

Supposons qu’une application Angular permette aux utilisateurs de saisir leur nom, qui est ensuite affiché dans un message de bienvenue. Un attaquant saisit le texte suivant :

{{constructor.constructor(‘alert(« XSS »)’)()}}

L’application utilise l’interpolation pour afficher le nom de l’utilisateur :

<p>Bienvenue, {{userName}}</p>

Dans ce cas, Angular ne parvient pas à empêcher l’exécution du code malveillant, car l’attaquant a exploité la fonction d’évaluation des expressions d’Angular.

Pour résoudre ce problème, assure-toi de valider et de désinfecter les entrées utilisateur avant de les utiliser dans des expressions interpolées. Utilise également le DomSanitizer lorsque tu travailles avec du contenu HTML dynamique.

Assure-toi de valider et désinfecter tes entrées utilisateur avant de les utiliser dans des expressions interpolées. Utilise également le DomSanitizer lorsque tu travailles avec du contenu HTML dynamique. Veille à bien effectuer ces étapes pour garantir la sécurité des données que tu reçois de l’utilisateur

3.3 Injection de code dans les templates Angular

Considérons une application Angular qui utilise les attributs de modèle pour générer dynamiquement des éléments de formulaire. Un attaquant peut injecter du code malveillant en insérant un attribut ng-attr-* dans le template :

<input ng-attr-type= »{{type}} » ng-model= »inputValue » />

L’attaquant pourrait définir type sur une valeur malveillante, comme suit :

javascript:alert(‘XSS’);

Pour éviter cette vulnérabilité, n’utilise pas les attributs de modèle pour générer dynamiquement des éléments de formulaire ou d’autres éléments sensibles. Utilise plutôt les directives Angular et les composants pour créer ces éléments de manière sécurisée. De plus, assure-toi de valider et désinfecter les entrées utilisateur avant de les utiliser dans ton application.

4. Solutions pour sécuriser ton application Angular​

4.1 Validation des entrées utilisateur

La validation des entrées utilisateur est cruciale pour prévenir les injections de code et autres attaques. Utilise des expressions régulières et des contraintes de validation pour t’assurer que les données saisies sont conformes aux attentes. Angular fournit des outils intégrés pour la validation des formulaires, tels que les Validators pour les Reactive Forms et les attributs de validation pour les Template-driven Forms.

Exemple de validation avec Reactive Forms:

import { FormBuilder, FormGroup, Validators } from ‘@angular/forms’;

constructor(private formBuilder: FormBuilder) {
    this.createForm();
}

createForm() {
    this.myForm = this.formBuilder.group({
        username: [ », Validators.required],
        email: [ », [Validators.required, Validators.email]],
    });
}

4.2 Protection contre les attaques CSRF

Les attaques Cross-Site Request Forgery (CSRF) exploitent la confiance d’une application en ses utilisateurs authentifiés. Pour prévenir ces attaques, utilise des tokens CSRF pour vérifier que les requêtes sont effectivement initiées par l’utilisateur authentifié. La plupart des frameworks back-end modernes incluent des mécanismes de protection CSRF. Intègre ces mécanismes avec Angular en ajoutant le token CSRF aux en-têtes des requêtes HttpClient.

Exemple d’intercepteur pour ajouter un token CSRF: 

import { HttpInterceptor, HttpRequest, HttpHandler, HttpHeaders } from ‘@angular/common/http’;

@Injectable()

export class CsrfInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler) {
        const csrfToken = document.cookie.match(‘(^|;)\\s*XSRF-TOKEN\\s*=\\s*([^;]+)’)?.pop() ||  »;
        const csrfHeader = new HttpHeaders().set(‘X-XSRF-TOKEN’, csrfToken);
        const csrfReq = req.clone({ headers: req.headers.set(‘X-XSRF-TOKEN’, csrfToken) });
        return next.handle(csrfReq);
    }
}

4.3 Utilisation de directives sécurisées pour le rendu conditionnel

Évite d’utiliser l’interpolation pour le rendu conditionnel d’éléments sensibles. Utilise plutôt des directives sécurisées comme *ngIf et *ngFor pour afficher ou masquer des éléments en fonction des conditions.

Exemple d’utilisation de *ngIf:

<button *ngIf= »isAdmin » (click)= »deleteUser() »>Supprimer l’utilisateur</button>

Dans cet exemple, le bouton « Supprimer l’utilisateur » ne sera affiché que si la propriété « isAdmin » est vraie.

4.4 Gestion sécurisée des cookies et du stockage local

Les cookies et le stockage local peuvent contenir des données sensibles, telles que des tokens d’authentification. Pour protéger ces données, utilise des attributs de sécurité de cookie appropriés, tels que Secure, HttpOnly et SameSite, et n’utilise pas le stockage local pour stocker des informations sensibles.

4.5 Authentification et autorisation

Implémente des mécanismes d’authentification et d’autorisation robustes pour protéger les données et les fonctionnalités sensibles. Utilise des solutions d’authentification standard, telles que OAuth 2.0 ou OpenID Connect, et assure-toi que ton API vérifie l’autorisation des utilisateurs avant de traiter leurs requêtes. Gére les autorisations côté serveur autant que possible, et ne pas te fier uniquement aux contrôles d’accès côté client.

4.6 Mise en place d’une politique de sécurité du contenu (CSP)

Une politique de sécurité du contenu (CSP) aide à protéger ton application contre les attaques XSS et d’autres injections de code. Configure une CSP stricte pour ton application Angular en définissant les sources de contenu autorisées pour les scripts, les styles, les images et d’autres ressources. Une CSP bien configurée limite l’impact des vulnérabilités de sécurité potentielles (voir section 2.2 pour un exemple de CSP et sa mise en œuvre).

4.7 Utilisation de la sécurité des transports

Utilise HTTPS pour crypter les communications entre ton application Angular et le serveur. HTTPS protège les données transmises contre les interceptions et les modifications par des tiers malveillants. Assure-toi que ton serveur Web est configuré pour utiliser HTTPS et redirige toutes les requêtes HTTP non sécurisées vers HTTPS.

4.8 Mise à jour régulière des dépendances

Garde les dépendances de ton application Angular à jour pour bénéficier des dernières fonctionnalités de sécurité et des correctifs de vulnérabilités. Utilise des outils tels que npm-audit ou Dependabot pour identifier et corriger les dépendances vulnérables.

4.9 Sensibilisation à la sécurité et formation des développeurs

Sensibilise tes collègues développeurs aux meilleures pratiques de sécurité et forme-les à la prévention des vulnérabilités courantes. Encourage les revues de code axées sur la sécurité et effectue des tests de pénétration pour identifier les problèmes de sécurité potentiels avant qu’ils ne soient exploités.

En appliquant ces mesures de sécurité, tu peux minimiser les risques associés aux vulnérabilités et aux failles, protégeant ainsi ton application Angular et les données de tes utilisateurs.

QCM

Testez vos connaissances sur ce sujet

TL;DR

  1. Les bases de la sécurité dans Angular et différents types d’attaques courantes
  2. Comment mettre en œuvre la désinfection du contenu, la gestion des tokens CSRF et l’utilisation d’intercepteurs HttpClient.
  3. Les solutions pour sécuriser ton application Angular