Comprendre l'autorité ambiante et les capabilités objet en sécurité informatique
Autorité Ambiante vs Capabilités Objet en Sécurité Informatique
L’autorité ambiante est un modèle de sécurité problématique où des privilèges sont accessibles de manière implicite. À l’inverse, les capabilités objet garantissent une gestion explicite des accès, réduisant ainsi les vulnérabilités. Cet article illustre ces concepts avec du C++.
Comprendre l’Autorité Ambiante
Définition : Une autorité est dite ambiante lorsqu'un programme peut accéder à une ressource sans passer par un mécanisme explicite d’autorisation.
Problème : Ce modèle entraîne des failles de sécurité, comme :
- Problème du député confus/'Confused deputy problem' : Un programme peut, involontairement être manipulé pour effectuer des actions malveillantes en utilisant son autorité implicite.
- Mauvaise gestion des accès : Les privilèges sont trop largement distribués, ce qui complique le contrôle et la surveillance.
Exemple en C++ : Mauvaise pratique
Dans l’exemple suivant, la fonction withdraw()
accède directement à une variable globale, ce qui illustre une 'autorité ambiante'.
#include <iostream>
double globalBalance = 1000.0; // Mauvaise pratique : Autorité ambiante
void withdraw(double amount) {
if (amount > globalBalance) {
std::cerr << "Fonds insuffisants !" << std::endl;
return;
}
globalBalance -= amount;
std::cout << "Retrait : " << amount << ", Solde restant : " << globalBalance << std::endl;
}
int main() {
withdraw(200); // Accès implicite aux fonds
withdraw(1000); // Sécurité compromise
return 0;
}
Problèmes :
- La variable
globalBalance
est accessible de partout. - Aucune restriction pour appeler
withdraw()
. - Une attaque peut manipuler l’autorité ambiante pour vider le compte.
Les Capabilités Objet : Une Sécurité Renforcée
Dans un modèle basé sur les capabilités objet, une ressource ne peut être accédée qu'à travers une référence spécifique (nécessitent des références explicites à des objets qui encapsulent l'autorité).
Avantages :
- Encapsulation : Seules les instances autorisées peuvent accéder aux données. (Evidence pour l'OOP)
- Moins de risques : Pas d'accès global incontrôlé.
- Facilité d’audit : Il est plus simple d’identifier qui a accès à quoi.
Ainsi, sachons que, les avantages de la programmation orientée-objet (OOP), comme l'encapsulation, la modularité et la séparation des préoccupations ou tâches, correspondent à un objectif de sécurité dans la programmation basée sur les 'capacités'
Exemple-1 en C++ : Bonne pratique
Ici, l'autorité est explicitement contrôlée par la classe BankAccount
.
#include <iostream>
class BankAccount {
private:
double balance;
public:
explicit BankAccount(double initialBalance) : balance(initialBalance) {}
void withdraw(double amount) {
if (amount > balance) {
std::cerr << "Fonds insuffisants !" << std::endl;
return;
}
balance -= amount;
std::cout << "Retrait : " << amount << ", Solde restant : " << balance << std::endl;
}
};
int main() {
BankAccount myAccount(1000.0); // Autorité encapsulée
myAccount.withdraw(200); // Accès contrôlé
myAccount.withdraw(1000); // Impossible de dépasser le solde autorisé
return 0;
}
Qu'apercevons-nous & pourquoi cette approche est-elle meilleure ?
- Ici, il n'y pas d'accès global et seul l'objet
BankAccount
peut modifier le solde. - Nous avons une meilleure gestion des accès car l'autorité est accordée uniquement à certaines instances.
- Il y a peu de vulnérabilités et les programmes malveillants ne peuvent pas manipuler l’état global.
Object Capability semble utiliser OOP (lambda calculus + local side effects + method dispatch) comme paradigme de programmation sous-jacent (paradigme de calcul intrinsèquement modulaire et sécurisé) favorisant la modularité dans la conception du code et une encapsulation fiable. Par conséquent, il peut être plus facile d'analyser les propriétés de sécurité, par exemple : les propriétés du flux d'informations, objets de stockage tels que des pages et des segments.
Exemple-2 : Pratique rafinée - 'Capacités Fortes'
#include <iostream>
#include <string>
#include <memory>
class File {
public:
File(const std::string& name) : filename(name) {}
void deleteFile() {
std::cout << "Suppression du fichier : " << filename << std::endl;
// Logique de suppression de fichier ici
}
private:
std::string filename;
};
class FileCapability {
public:
FileCapability(std::shared_ptr<File> file) : file(file) {}
void deleteFile() {
file->deleteFile();
}
private:
std::shared_ptr<File> file;
};
class User {
public:
User(const std::string& name) : username(name) {}
void deleteFile(FileCapability& capability) {
std::cout << "L'utilisateur " << username << " supprime un fichier." << std::endl;
capability.deleteFile();
}
private:
std::string username;
};
int main() {
auto file = std::make_shared<File>("important.txt");
FileCapability capability(file);
User user("Alice");
user.deleteFile(capability);
return 0;
}
Dans cet exemple, FileCapability
encapsule l'autorité de supprimer un fichier, et User
utilise explicitement cette capacité pour supprimer le fichier.
Spécification d'Implémentation
- Définir correctement des Classes pour les Ressources : 'classes -> ressources' (par exemple,
File
). - Toujours encapsuler l'Autorité en utilisant des classes comme
FileHandle
ouFileCapability
pour encapsuler l'autorité. - Accorder Explicitement l'Autorité en s'assurant que l'autorité est explicitement accordée en passant par des 'objets de capacité' (.
- Utiliser une forte saisie pour garantir que seules les entités autorisées peuvent effectuer des actions
Implémentation Parfaite
Pour implémenter cela parfaitement, assurez-vous que :
- Toute autorité est encapsulée dans des objets.
- L'autorité est explicitement accordée et utilisée.
- Pour la gestion de la mémoire: Une analogie entre les capacités et les pointeurs est instructive. Un pointeur désigne un objet informatique. Cependant, un pointeur n'est pas protégé et les modèles de bits non destinés à être des pointeurs causent des ravages lorsqu'ils sont mal utilisés. Et pourquoi cela? Bien, l’utilisation des concepts élémentaires comme 'character, variable, array, integer, data & program, address (resource locator), atomic transaction' ont des significations abstraites et pour exécuter un programme, nous en avons besoin pour des 'implémentations concrètes'. Cependant, les problèmes de sécurité logicielle surviennent lorsque la mise en œuvre concrète et l’intuition abstraite divergent.
- Implémentez une gestion des erreurs et un carnet d'exploitation (logging) appropriés.
Cette approche garantit un système sécurisé, maintenable et efficace qui évite les pièges de l'autorité ambiante.
Conclusion
Éviter l’autorité ambiante est essentiel pour renforcer la sécurité d’un système. En utilisant les capabilités objet, nous obtenons :
- Un contrôle explicite des accès.
- Une réduction des risques liés aux attaques.
- Un code plus sûr et maintenable.
En résumé, bien que le modèle de capacité objet offre un potentiel élevé pour renforcer la sécurité logicielle, son utilisation reste marginale en raison d'un manque de connaissance et de pratiques alternatives plus commodes. Des efforts pour promouvoir son adoption, via des bibliothèques de modèles et une meilleure éducation des développeurs, pourraient contribuer à une utilisation plus répandue de ce modèle sécurisé.
P.s.
Pour garantir la sécurité dans vos projets C++, privilégiez toujours un modèle basé sur les capabilités objet. !
Comments
Post a Comment