Explorez les modèles de type TypeScript pour la sanitisation des entrées afin de créer des applications sécurisées et fiables. Apprenez à prévenir les vulnérabilités courantes comme les attaques XSS et par injection.
Sécurité TypeScript : Modèles de type pour la sanitisation des entrées pour des applications robustes
Dans le monde interconnecté d'aujourd'hui, la création d'applications web sécurisées et fiables est primordiale. Avec la sophistication croissante des cybermenaces, les développeurs doivent employer des mesures de sécurité robustes pour protéger les données sensibles et prévenir les attaques malveillantes. TypeScript, avec son système de typage fort, fournit des outils puissants pour améliorer la sécurité des applications, notamment grâce à des modèles de type pour la sanitisation des entrées. Ce guide complet explore divers modèles de type TypeScript pour la sanitisation des entrées, vous permettant de créer des applications plus sûres et plus résilientes.
Pourquoi la sanitisation des entrées est-elle cruciale ?
La sanitisation des entrées est le processus de nettoyage ou de modification des données fournies par l'utilisateur pour éviter qu'elles ne causent des dommages à l'application ou à ses utilisateurs. Les données non fiables, qu'elles proviennent de soumissions de formulaires, de requêtes API ou de toute autre source externe, peuvent introduire des vulnérabilités telles que :
- Cross-Site Scripting (XSS) : Les attaquants injectent des scripts malveillants dans les pages web consultées par d'autres utilisateurs.
- Injection SQL : Les attaquants insèrent du code SQL malveillant dans les requêtes de base de données.
- Injection de commandes : Les attaquants exécutent des commandes arbitraires sur le serveur.
- Path Traversal : Les attaquants accèdent à des fichiers ou répertoires non autorisés.
Une sanitisation efficace des entrées atténue ces risques en s'assurant que toutes les données traitées par l'application sont conformes aux formats attendus et ne contiennent pas de contenu nuisible.
Tirer parti du système de types de TypeScript pour la sanitisation des entrées
Le système de types de TypeScript offre plusieurs avantages pour la mise en œuvre de la sanitisation des entrées :
- Analyse statique : Le compilateur de TypeScript peut détecter les erreurs potentielles liées aux types pendant le développement, avant l'exécution.
- Sécurité des types : Applique les types de données, réduisant le risque de formats de données inattendus.
- Clarté du code : Améliore la lisibilité et la maintenabilité du code grâce à des déclarations de type explicites.
- Support au refactoring : Facilite la refonte du code tout en maintenant la sécurité des types.
En tirant parti du système de types de TypeScript, les développeurs peuvent créer des mécanismes robustes de sanitisation des entrées qui minimisent le risque de vulnérabilités de sécurité.
Modèles de type courants pour la sanitisation des entrées en TypeScript
1. Sanitisation des chaînes de caractères
La sanitisation des chaînes de caractères consiste à nettoyer et à valider les entrées de type chaîne pour prévenir les attaques XSS et autres attaques par injection. Voici quelques techniques courantes :
a. Échappement des entités HTML
L'échappement des entités HTML convertit les caractères potentiellement dangereux en leurs entités HTML correspondantes, les empêchant d'être interprétés comme du code HTML. Par exemple, < devient <, et > devient >.
Exemple :
function escapeHtml(str: string): string {
const map: { [key: string]: string } = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return str.replace(/[&<>\"']/g, (m) => map[m]);
}
const userInput: string = '';
const sanitizedInput: string = escapeHtml(userInput);
console.log(sanitizedInput); // Sortie : <script>alert("XSS");</script>
b. Validation par expression régulière
Les expressions régulières peuvent être utilisées pour valider qu'une chaîne de caractères est conforme à un format spécifique, comme une adresse e-mail ou un numéro de téléphone.
Exemple :
function isValidEmail(email: string): boolean {
const emailRegex: RegExp = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
return emailRegex.test(email);
}
const email1: string = 'test@example.com';
const email2: string = 'invalid-email';
console.log(isValidEmail(email1)); // Sortie : true
console.log(isValidEmail(email2)); // Sortie : false
c. Alias de type pour des formats de chaîne spécifiques
Les alias de type de TypeScript peuvent être utilisés pour définir des formats de chaîne spécifiques et les appliquer au moment de la compilation.
Exemple :
type Email = string & { readonly __email: unique symbol };
function createEmail(input: string): Email {
if (!isValidEmail(input)) {
throw new Error('Format d\'email invalide');
}
return input as Email;
}
try {
const validEmail: Email = createEmail('test@example.com');
console.log(validEmail); // Sortie : test@example.com (avec le type Email)
const invalidEmail = createEmail('invalid-email'); // Lance une erreur
} catch (error) {
console.error(error);
}
2. Sanitisation des nombres
La sanitisation des nombres consiste à valider que les entrées numériques se situent dans des plages acceptables et sont conformes aux formats attendus.
a. Validation de plage
S'assurer qu'un nombre se situe dans une plage spécifique.
Exemple :
function validateAge(age: number): number {
if (age < 0 || age > 120) {
throw new Error('Âge invalide : l\'âge doit être compris entre 0 et 120.');
}
return age;
}
try {
const validAge: number = validateAge(30);
console.log(validAge); // Sortie : 30
const invalidAge: number = validateAge(150); // Lance une erreur
} catch (error) {
console.error(error);
}
b. Gardes de type pour les types numériques
Utilisez des gardes de type pour vous assurer qu'une valeur est un nombre avant d'effectuer des opérations dessus.
Exemple :
function isNumber(value: any): value is number {
return typeof value === 'number' && isFinite(value);
}
function processNumber(value: any): number {
if (!isNumber(value)) {
throw new Error('Entrée invalide : l\'entrée doit être un nombre.');
}
return value;
}
try {
const validNumber: number = processNumber(42);
console.log(validNumber); // Sortie : 42
const invalidNumber: number = processNumber('not a number'); // Lance une erreur
} catch (error) {
console.error(error);
}
3. Sanitisation des dates
La sanitisation des dates consiste à valider que les entrées de date sont au bon format et dans des plages acceptables.
a. Validation du format de date
Utilisez des expressions régulières ou des bibliothèques d'analyse de dates pour vous assurer qu'une chaîne de date est conforme à un format spécifique (par exemple, YYYY-MM-DD).
Exemple :
function isValidDate(dateString: string): boolean {
const dateRegex: RegExp = /^\d{4}-\d{2}-\d{2}$/;
if (!dateRegex.test(dateString)) {
return false;
}
const date: Date = new Date(dateString);
return !isNaN(date.getTime());
}
function parseDate(dateString: string): Date {
if (!isValidDate(dateString)) {
throw new Error('Format de date invalide : la date doit être au format YYYY-MM-DD.');
}
return new Date(dateString);
}
try {
const validDate: Date = parseDate('2023-10-27');
console.log(validDate); // Sortie : Fri Oct 27 2023 00:00:00 GMT+0000 (Temps universel coordonné)
const invalidDate: Date = parseDate('2023/10/27'); // Lance une erreur
} catch (error) {
console.error(error);
}
b. Validation de la plage de dates
S'assurer qu'une date se situe dans une plage spécifique, comme une date de début et une date de fin.
Exemple :
function isDateWithinRange(date: Date, startDate: Date, endDate: Date): boolean {
return date >= startDate && date <= endDate;
}
function validateDateRange(dateString: string, startDateString: string, endDateString: string): Date {
const date: Date = parseDate(dateString);
const startDate: Date = parseDate(startDateString);
const endDate: Date = parseDate(endDateString);
if (!isDateWithinRange(date, startDate, endDate)) {
throw new Error('Date invalide : la date doit être comprise entre les dates de début et de fin.');
}
return date;
}
try {
const validDate: Date = validateDateRange('2023-10-27', '2023-01-01', '2023-12-31');
console.log(validDate); // Sortie : Fri Oct 27 2023 00:00:00 GMT+0000 (Temps universel coordonné)
const invalidDate: Date = validateDateRange('2024-01-01', '2023-01-01', '2023-12-31'); // Lance une erreur
} catch (error) {
console.error(error);
}
4. Sanitisation des tableaux
La sanitisation des tableaux consiste à valider les éléments d'un tableau pour s'assurer qu'ils répondent à des critères spécifiques.
a. Gardes de type pour les éléments de tableau
Utilisez des gardes de type pour vous assurer que chaque élément d'un tableau est du type attendu.
Exemple :
function isStringArray(arr: any[]): arr is string[] {
return arr.every((item) => typeof item === 'string');
}
function processStringArray(arr: any[]): string[] {
if (!isStringArray(arr)) {
throw new Error('Entrée invalide : le tableau ne doit contenir que des chaînes de caractères.');
}
return arr;
}
try {
const validArray: string[] = processStringArray(['apple', 'banana', 'cherry']);
console.log(validArray); // Sortie : [ 'apple', 'banana', 'cherry' ]
const invalidArray: string[] = processStringArray(['apple', 123, 'cherry']); // Lance une erreur
} catch (error) {
console.error(error);
}
b. Sanitisation des éléments de tableau
Appliquez des techniques de sanitisation à chaque élément d'un tableau pour prévenir les attaques par injection.
Exemple :
function sanitizeStringArray(arr: string[]): string[] {
return arr.map(escapeHtml);
}
const inputArray: string[] = ['', 'normal text'];
const sanitizedArray: string[] = sanitizeStringArray(inputArray);
console.log(sanitizedArray);
// Sortie : [ '<script>alert("XSS");</script>', 'normal text' ]
5. Sanitisation des objets
La sanitisation des objets consiste à valider les propriétés d'un objet pour s'assurer qu'elles répondent à des critères spécifiques.
a. Assertions de type pour les propriétés d'objet
Utilisez des assertions de type pour appliquer les types des propriétés d'objet.
Exemple :
interface User {
name: string;
age: number;
email: Email;
}
function validateUser(user: any): User {
if (typeof user.name !== 'string') {
throw new Error('Utilisateur invalide : le nom doit être une chaîne de caractères.');
}
if (typeof user.age !== 'number') {
throw new Error('Utilisateur invalide : l\'âge doit être un nombre.');
}
if (typeof user.email !== 'string' || !isValidEmail(user.email)) {
throw new Error('Utilisateur invalide : l\'email doit être une adresse email valide.');
}
return {
name: user.name,
age: user.age,
email: createEmail(user.email)
};
}
try {
const validUser: User = validateUser({
name: 'John Doe',
age: 30,
email: 'john.doe@example.com',
});
console.log(validUser);
// Sortie : { name: 'John Doe', age: 30, email: [Email: john.doe@example.com] }
const invalidUser: User = validateUser({
name: 'John Doe',
age: '30',
email: 'invalid-email',
}); // Lance une erreur
} catch (error) {
console.error(error);
}
b. Sanitisation des propriétés d'objet
Appliquez des techniques de sanitisation à chaque propriété d'un objet pour prévenir les attaques par injection.
Exemple :
interface Product {
name: string;
description: string;
price: number;
}
function sanitizeProduct(product: Product): Product {
return {
name: escapeHtml(product.name),
description: escapeHtml(product.description),
price: product.price,
};
}
const inputProduct: Product = {
name: '',
description: 'This is a product description with some HTML.',
price: 99.99,
};
const sanitizedProduct: Product = sanitizeProduct(inputProduct);
console.log(sanitizedProduct);
// Sortie : { name: '<script>alert("XSS");</script>', description: 'This is a product description with some <b>HTML</b>.', price: 99.99 }
Bonnes pratiques pour la sanitisation des entrées en TypeScript
- Sanitiser tôt : Sanitisez les données aussi près que possible de la source d'entrée.
- Utilisez une approche de défense en profondeur : Combinez la sanitisation des entrées avec d'autres mesures de sécurité, telles que l'encodage des sorties et les requêtes paramétrées.
- Maintenez la logique de sanitisation à jour : Restez informé des dernières vulnérabilités de sécurité et mettez à jour votre logique de sanitisation en conséquence.
- Testez votre logique de sanitisation : Testez minutieusement votre logique de sanitisation pour vous assurer qu'elle prévient efficacement les attaques par injection.
- Utilisez des bibliothèques reconnues : Tirez parti de bibliothèques bien maintenues et fiables pour les tâches de sanitisation courantes, plutôt que de réinventer la roue. Par exemple, envisagez d'utiliser une bibliothèque comme validator.js.
- Pensez à la localisation : Lorsque vous traitez des entrées d'utilisateurs de différentes régions, soyez conscient des différents jeux de caractères et normes d'encodage (par exemple, UTF-8). Assurez-vous que votre logique de sanitisation gère correctement ces variations pour éviter d'introduire des vulnérabilités liées aux problèmes d'encodage.
Exemples de considérations sur les entrées globales
Lors du développement d'applications pour un public mondial, il est crucial de tenir compte des divers formats d'entrée et conventions culturelles. Voici quelques exemples :
- Formats de date : Différentes régions utilisent différents formats de date (par exemple, MM/DD/YYYY aux États-Unis, DD/MM/YYYY en Europe). Assurez-vous que votre application peut gérer plusieurs formats de date et fournir une validation appropriée.
- Formats de nombre : Différentes régions utilisent différents séparateurs pour les décimales et les milliers (par exemple, 1,000.00 aux États-Unis, 1.000,00 en Europe). Utilisez des bibliothèques d'analyse et de formatage appropriées pour gérer ces variations.
- Symboles monétaires : Les symboles monétaires varient selon les pays (par exemple, $, €, £). Utilisez une bibliothèque de formatage de devises pour afficher correctement les valeurs monétaires en fonction des paramètres régionaux de l'utilisateur.
- Formats d'adresse : Les formats d'adresse varient considérablement d'un pays à l'autre. Fournissez des champs de saisie flexibles et une logique de validation pour s'adapter aux différentes structures d'adresse.
- Formats de nom : Les formats de nom diffèrent d'une culture à l'autre (par exemple, les noms occidentaux ont généralement un prénom suivi d'un nom de famille, tandis que certaines cultures asiatiques inversent l'ordre). Envisagez de permettre aux utilisateurs de spécifier leur ordre de nom préféré.
Conclusion
La sanitisation des entrées est un aspect essentiel de la création d'applications TypeScript sécurisées et fiables. En tirant parti du système de types de TypeScript et en mettant en œuvre des modèles de type de sanitisation appropriés, les développeurs peuvent réduire considérablement le risque de vulnérabilités de sécurité telles que les attaques XSS et par injection. N'oubliez pas de sanitiser tôt, d'utiliser une approche de défense en profondeur et de vous tenir informé des dernières menaces de sécurité. En suivant ces bonnes pratiques, vous pouvez créer des applications plus robustes et sécurisées qui protègent vos utilisateurs et leurs données. Lorsque vous développez des applications mondiales, gardez toujours à l'esprit les conventions culturelles pour garantir une expérience utilisateur positive.
Ce guide fournit une base solide pour comprendre et mettre en œuvre la sanitisation des entrées en TypeScript. Cependant, la sécurité est un domaine en constante évolution. Restez toujours à jour sur les dernières bonnes pratiques et vulnérabilités pour protéger efficacement vos applications.