Nouveau : Datasets open source gratuits disponibles !Decouvrir →
🟢
Intermediaire 25 min NestJS

Securiser une application NestJS

Pourquoi Securiser une application NestJS ?

Dans un monde où les données personnelles et sensibles sont à la hauteur de la priorité, il est crucial de sécuriser toute application, y compris celles développées avec NestJS. En tant que développeur senior, vous avez probablement déjà confronté des situations où la sécurité a été compromise, par exemple lors d'un accès non autorisé ou une perte de données sensibles.

Un cas d'usage concret serait le développement d'une application de gestion de la santé en ligne. Si cette application n'était pas sécurisée, elle pourrait être vulnérable aux attaques telles que l'injection SQL ou les failles XSS (Cross-Site Scripting), ce qui pourrait entraîner une perte de confidentialité des informations des patients.

Prerequis

  • Connaissances nécessaires :

    • Maîtrise avancée d'NestJS, en particulier le système d'injection de dépendance et les routes.
    • Compréhension du principe de base de la sécurité Web (CSP, CORS, HTTPS).
    • Connaissance des mécanismes de contrôle d'accès et de gestion des rôles.
  • Outils à installer :

    • Node.js (v14.0.0 ou ultérieur)
    • npm (Node Package Manager) pour gérer les dépendances
    • NestJS CLI pour créer le projet

Concepts fondamentaux

1. Authentification et Autorisation

L'authentification est le processus par lequel un utilisateur est identifié, tandis que l'autorisation est le processus par lequel on vérifie si cet utilisateur a les droits nécessaires pour effectuer une action spécifique.

// auth.service.ts
import { Injectable } from '@nestjs/common';
import * as bcrypt from 'bcrypt';

@Injectable()
export class AuthService {
  async validateUser(username: string, pass: string): Promise<any> {
    const user = await this.findOne(username); // Méthode hypothétique pour récupérer un utilisateur
    if (user && await bcrypt.compare(pass, user.password)) {
      const { password, ...result } = user;
      return result;
    }
    return null;
  }

  async hashPassword(password: string): Promise<string> {
    return bcrypt.hash(password, 10);
  }
}

2. Middleware

Les middleware sont des fonctions qui ont accès à l'objet de requête (req), à l'objet de réponse (res) et à la fonction de rappel de la chaîne de middleware suivante dans le cycle de traitement d'une requête/réponse. Ils sont utilisés pour effectuer des tâches telles que la validation, la manipulation des données ou la gestion des erreurs.

// auth.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class AuthMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const token = req.headers['authorization'];
    if (token && token === 'valid_token') {
      next();
    } else {
      res.status(403).send({ message: 'Unauthorized' });
    }
  }
}

3. JWT (JSON Web Tokens)

Les tokens JWT sont des tokens de sécurité qui permettent d'assurer l'intégrité et la validité des données transmises entre le client et le serveur.

// jwt.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: 'secret',
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

4. CORS (Cross-Origin Resource Sharing)

CORS est un mécanisme qui utilise des en-têtes HTTP pour indiquer que les ressources d'une application Web peuvent être accédées depuis une origine différente.

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as cors from 'cors';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(cors({
    origin: 'http://example.com',
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
    credentials: true,
  }));
  await app.listen(3000);
}
bootstrap();

Mise en pratique : projet fil rouge

Étape 1 : Création du projet NestJS

nest new task-manager
cd task-manager
npm install @nestjs/passport passport passport-jwt bcryptjs

Étape 2 : Configuration de l'authentification

Créez un service d'authentification.

// src/auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import * as bcrypt from 'bcrypt';

@Injectable()
export class AuthService {
  async validateUser(username: string, pass: string): Promise<any> {
    const user = await this.findOne(username); // Méthode hypothétique pour récupérer un utilisateur
    if (user && await bcrypt.compare(pass, user.password)) {
      const { password, ...result } = user;
      return result;
    }
    return null;
  }

  async hashPassword(password: string): Promise<string> {
    return bcrypt.hash(password, 10);
  }

  private findOne(username: string): Promise<any> {
    // Logique pour récupérer un utilisateur
    return { username, password: 'hashed_password', id: 1 };
  }
}

Étape 3 : Configuration du JWT

Créez un strategy de stratégie.

// src/auth/jwt.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: 'secret',
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

Étape 4 : Création du middleware d'authentification

// src/auth/auth.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class AuthMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const token = req.headers['authorization'];
    if (token && token === 'valid_token') {
      next();
    } else {
      res.status(403).send({ message: 'Unauthorized' });
    }
  }
}

Étape 5 : Ajout des routes sécurisées

// src/task/task.controller.ts
import { Controller, Get, UseGuards, Request } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Controller('task')
@UseGuards(AuthGuard('jwt'))
export class TaskController {
  @Get()
  getTasks(@Request() req) {
    return `This action returns all tasks for ${req.user.username}`;
  }
}

Erreurs frequentes et debugging

1. Token invalide

## ❌ Mauvais
res.status(403).send({ message: 'Unauthorized' });

## ✅ Correct
const token = req.headers['authorization'];
if (token && token === 'valid_token') {
  next();
} else {
  res.status(401).send({ message: 'Invalid token' });
}

2. Erreur de validation des données

## ❌ Mauvais
const user = await this.findOne(username); // Méthode hypothétique pour récupérer un utilisateur
if (user && await bcrypt.compare(pass, user.password)) {
  const { password, ...result } = user;
  return result;
}
return null;

## ✅ Correct
try {
  const user = await this.authService.validateUser(username, pass);
  if (!user) {
    throw new UnauthorizedException('Invalid credentials');
  }
  return user;
} catch (error) {
  throw error;
}

3. Erreur de configuration CORS

## ❌ Mauvais
app.use(cors());

## ✅ Correct
app.use(cors({
  origin: 'http://example.com',
  methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
  credentials: true,
}));

Pour aller plus loin

1. Authentification par Google ou Facebook

Pour intégrer l'authentification via des comptes sociaux populaires.

2. Gestion fine des rôles et permissions

Pour définir différents niveaux d'accès aux ressources de l'application.

3. Sécurité des données sensibles

Pour chiffrer les données sensibles stockées dans la base de données.

Défi pratique

Développez une API pour un blog avec les fonctionnalités suivantes :

  • Authentification utilisateurs
  • Création, lecture, mise à jour et suppression d'articles
  • Gestion des commentaires

Conseils : Utilisez le système d'injection de dépendance d'NestJS pour structurer votre application. Assurez-vous que toutes les routes nécessitent une authentification valide.


Ce tutoriel vous aide à comprendre et mettre en œuvre les principes de base de la sécurité dans une application NestJS. En suivant ces étapes, vous serez prêt à sécuriser vos applications Web et protéger les données des utilisateurs.

Besoin d'aide sur NestJS ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Questions frequentes

Quelles sont les meilleures pratiques pour sécuriser une application NestJS ?
Pour sécuriser une application NestJS, il est recommandé d'implémenter des mesures telles que l'utilisation de HTTPS, la validation et la normalisation des entrées utilisateurs, le hachage des mots de passe, la gestion des sessions sécurisées, et la protection contre les injections SQL et les XSS. Il est également important de mettre en œuvre un contrôle d'accès fine-grained et de surveiller régulièrement les journaux pour détecter les activités suspectes.
Comment configurer l'authentification JWT dans une application NestJS ?
Pour configurer l'authentification JWT dans une application NestJS, vous devez d'abord installer le package `@nestjs/jwt` et `passport-jwt`. Ensuite, configurez un service pour gérer la génération et la vérification des tokens JWT. Ajoutez également des guards comme `AuthGuard('jwt')` à vos contrôleurs pour protéger les routes nécessitant une authentification.
Quelle est la meilleure façon de gérer le stockage sécurisé des mots de passe dans NestJS ?
La meilleure pratique consiste à utiliser un hachage fort comme BCrypt pour crypter les mots de passe avant de les stocker en base de données. Utilisez une salut unique générée aléatoirement pour chaque mot de passe et stockez-le avec le hash. Assurez-vous également d'utiliser des configurations sécurisées pour votre gestionnaire de mots de passe, comme un salage fort et un nombre de tours suffisant de hachage.

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.