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

  1. Définir correctement des Classes pour les Ressources : 'classes -> ressources' (par exemple, File).
  2. Toujours encapsuler l'Autorité en utilisant des classes comme FileHandle ou FileCapability pour encapsuler l'autorité.
  3. Accorder Explicitement l'Autorité en s'assurant que l'autorité est explicitement accordée en passant par des 'objets de capacité' (.
  4. 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

Popular posts from this blog

Les expressions régulières gourmandes & non gourmandes en C++

MANIFESTO DU DÉVELOPPEUR/PROGRAMMEUR TOGOLAIS

Refactorisation de Code avec les 10 Règles de la NASA