Aller au contenu

Sécurité par capacités contre ACL

La sécurité par capacités remplace la question « qui a le droit d’accéder à cette ressource ? » par « qui détient une référence non forgeable donnant ce droit ? ». Ce déplacement paraît subtil, mais il modifie la délégation, le confinement, la révocation et la topologie même des services.

→ Lire l’explication complète de la marmotte

Une ACL (Access Control List, liste de contrôle d’accès) est attachée à une ressource. Elle associe des identités, groupes ou rôles à des permissions. Lorsqu’une requête arrive, le service authentifie le demandeur, récupère ses attributs, puis compare ces éléments à la politique de la ressource. Ce modèle domine les systèmes de fichiers, les annuaires et les plateformes d’identité. Il reste le bon choix lorsqu’une autorité centrale doit répondre à la question : « quels droits possède cette identité partout ? »

Une capacité est une référence possédée par un sujet, non forgeable, qui désigne un objet et les opérations autorisées. La référence peut être un descripteur de fichier Unix, un jeton aléatoire stocké côté serveur, une URL signée ou un jeton cryptographiquement protégé. Détenir la capacité suffit à exercer le droit qu’elle représente, sous réserve des restrictions qu’elle embarque ou que le service vérifie.

Le compromis central est brutal : les capacités rendent la délégation fine, locale et composable, mais elles déplacent le problème de l’autorisation vers la garde et la révocation des jetons. Une ACL centralise la gouvernance et rend l’audit par identité plus naturel, au prix de vérifications répétées et de dépendances à l’annuaire. Une capacité réduit le couplage avec l’identité, mais un jeton copié est un droit copié. La magie s’arrête là, comme souvent juste après la troisième slide vendeur.

Le modèle par capacités doit être privilégié pour les échanges interservices, les liens de téléchargement à durée limitée, les accès à un objet précis et les délégations automatisées. Il ne faut pas l’utiliser seul pour l’administration humaine transverse, les droits réglementaires complexes ou les environnements où l’inventaire des détenteurs est une exigence de contrôle. Dans ces cas, une ACL ou une politique centralisée reste nécessaire.

La différence avec Bell-LaPadula et Biba est structurelle. Ces modèles formels définissent des règles de circulation de l’information selon des niveaux de confidentialité ou d’intégrité. Une capacité répond plutôt à la question opérationnelle de la possession d’un droit sur un objet. Elle peut implémenter une partie d’une politique formelle, mais ne prouve ni confidentialité globale ni intégrité globale. Les fondations de l’architecture cybersécurité gagnent à séparer ces couches au lieu de les mélanger dans une même soupe de diagrammes.

Une capacité bien conçue doit désigner une ressource, limiter les verbes autorisés, borner sa durée de vie et préciser son contexte d’usage. Un jeton donnant read sur un objet donné n’est pas interchangeable avec un jeton donnant admin sur un espace de stockage. Cette granularité est le bénéfice réel du modèle, pas la présence décorative d’un jeton opaque dans un en-tête HTTP.

La délégation doit être atténuante : un détenteur peut transmettre moins de droits, jamais davantage. Par exemple, un service de génération de rapports reçoit le droit de lire un export donné pendant cinq minutes, sans recevoir le droit de lister tous les exports ni de modifier le stockage. Si une délégation permet d’élargir les droits par modification d’un champ non signé, le système n’utilise pas des capacités, il utilise un mot de passe avec une moustache.

Une capacité ne doit jamais être dérivable à partir d’un identifiant prévisible. Un numéro de facture, un chemin de fichier, un identifiant universel ou une date ne constituent pas une capacité. Une référence doit être soit aléatoire avec au moins 128 bits d’entropie, soit protégée par une signature cryptographique couvrant intégralement ses restrictions. Dans le second cas, une modification de l’objet, de l’opération, de l’audience ou de l’expiration doit invalider la vérification.

Le confinement découle de l’absence d’autorité ambiante. Un composant ne devrait accéder qu’aux capacités explicitement reçues, pas à un compte de service capable de rechercher toutes les ressources. Un processus de traitement d’image recevant une capacité de lecture sur un fichier et une capacité d’écriture sur un résultat n’a aucune raison d’obtenir les identifiants du stockage global. Réduire l’autorité ambiante évite qu’une injection de code se transforme immédiatement en inventaire complet.

Cette discipline rejoint la gestion des identités, mais ne s’y réduit pas. L’authentification établit qui ou quoi présente une requête. La capacité établit ce que cette requête peut faire sur un objet. Mélanger les deux dans un jeton surchargé produit des droits difficiles à déléguer et impossibles à révoquer proprement.

Une URL signée peut servir de capacité pour télécharger un objet précis. L’exemple suivant génère puis vérifie un jeton contenant une ressource, une opération et une date d’expiration. Il utilise HMAC (Hash-based Message Authentication Code), avec SHA-256 (Secure Hash Algorithm 256 bits), et exige une clé secrète d’au moins 32 octets aléatoires.

# python3 capability.py
# Démonstration reproductible d'une capacité de lecture limitée dans le temps.
import base64, hashlib, hmac, json, os, time
secret = os.environ["CAPABILITY_HMAC_KEY"].encode()
def issue(object_id, ttl_seconds):
payload = {
"object": object_id,
"action": "read",
"expires": int(time.time()) + ttl_seconds,
}
raw = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode()
signature = hmac.new(secret, raw, hashlib.sha256).digest()
return base64.urlsafe_b64encode(raw + b"." + signature).decode()
def verify(token):
raw_and_signature = base64.urlsafe_b64decode(token.encode())
raw, signature = raw_and_signature.rsplit(b".", 1)
expected = hmac.new(secret, raw, hashlib.sha256).digest()
if not hmac.compare_digest(signature, expected):
raise PermissionError("signature invalide")
payload = json.loads(raw)
if payload["action"] != "read" or payload["expires"] < time.time():
raise PermissionError("capacité expirée ou opération refusée")
return payload["object"]
token = issue("exports/rapport-2026-09.csv", 300)
print(token)
print(verify(token))

Lancer avec export CAPABILITY_HMAC_KEY="$(openssl rand -hex 32)". En production, la clé HMAC ne doit pas résider dans une variable d’environnement partagée par tous les pods. La placer dans un HSM (Hardware Security Module) ou dans un service de signature isolé limite l’extraction, mais ne corrige pas une autorisation trop large du service appelant.

Cet exemple ne permet pas la révocation individuelle sans état serveur. Une signature valide reste valide jusqu’à expiration. Pour révoquer immédiatement une capacité, il faut ajouter un identifiant de jeton, vérifier une liste de révocation, ou conserver le jeton opaque dans un stockage transactionnel. Une expiration de cinq minutes n’est pas une révocation instantanée. C’est une expiration de cinq minutes, détail que les architectures découvrent souvent après l’incident.

Le vol de capacité est l’attaque principale. Les journaux HTTP, les référents, l’historique navigateur, les traces distribuées, les messages de file et les captures mémoire sont autant de canaux d’exfiltration. Une capacité placée dans une URL ne doit jamais transiter vers un domaine tiers, apparaître dans une page chargée avec des ressources externes, ni être conservée dans des journaux applicatifs. Préférer un en-tête d’autorisation lorsque le lien partageable n’est pas requis.

La confusion d’audience est la seconde attaque fréquente. Une capacité émise pour un service ne doit pas être acceptée par tous les services disposant de la même clé de signature. Inclure l’audience, l’émetteur, l’opération, la ressource et l’expiration dans les données signées. Utiliser une clé distincte par domaine d’autorisation limite le rayon d’explosion d’une compromission.

La révocation doit être choisie avant l’émission des premiers jetons. Trois stratégies existent :

  • durée de vie courte, acceptable pour les droits éphémères ;
  • registre côté serveur, nécessaire pour une révocation individuelle ;
  • rotation de clé, efficace pour couper une famille entière de capacités.

La rotation de clé invalide toutes les capacités signées avec l’ancienne clé si le vérificateur cesse de l’accepter. Elle n’est donc pas une réponse fine à un jeton compromis. Prévoir une fenêtre de double vérification avec identifiants de clé, puis retirer l’ancienne clé. Une clé sans identifiant transforme une rotation en petit exercice de divination opérationnelle.

Les clés de signature exigent inventaire, rotation, sauvegarde contrôlée et journalisation des usages. Une sauvegarde qui restaure une ancienne clé de signature peut réactiver des capacités que l’on croyait mortes. Les métadonnées de rotation doivent donc être cohérentes avec les sauvegardes, et la restauration doit déclencher une revue des clés acceptées.

La supervision doit mesurer les erreurs de signature, les expirations, les refus par audience et les tentatives de réutilisation. Un pic de signatures invalides peut signaler un client désynchronisé, mais aussi une falsification active. Ne pas journaliser le jeton brut : enregistrer son empreinte cryptographique, son identifiant et la décision prise permet l’investigation sans créer un dépôt de droits réutilisables.

Le modèle ne garantit pas l’identité du détenteur, la confidentialité d’un canal, la sécurité du poste client ou l’absence d’abus par un détenteur légitime. Il faut du chiffrement de transport, une authentification lorsque l’acteur compte, de la segmentation réseau et une politique de journalisation. Les mécanismes de cryptographie appliquée protègent les jetons contre la falsification, pas contre une capture dans un navigateur compromis.

Enfin, une capacité ne remplace pas l’autorisation métier. Le service émetteur doit avoir évalué la demande initiale avec une politique fiable. Émettre une capacité après une vérification laxiste propage simplement l’erreur sous une forme plus portable. Le jeton est alors impeccablement signé, ce qui est une manière très propre de distribuer un problème.

Sans capacités, un service qui agit pour le compte d’un client exerce sa propre autorité ambiante : c’est le problème du député confus. Un appelant peut alors désigner, par un simple nom de fichier ou un identifiant passé en paramètre, une ressource qu’il n’a pas le droit de toucher ; le service vérifie ses propres droits, pas ceux du demandeur, et exécute l’opération. La délégation entre composants retombe sur le partage d’identifiants de compte de service ou sur l’ajout de rôles larges dans l’ACL, jamais retirés une fois la tâche terminée. Les journaux attribuent ensuite chaque action au compte de service intermédiaire, ce qui efface l’origine réelle de la demande et empêche de reconstituer quelle requête initiale a provoqué quel accès.

Dans une liste de contrôle d’accès, un service reçoit une demande, identifie le demandeur puis cherche dans une liste si cette identité a le droit demandé. Avec une capacité, le demandeur présente un droit déjà délivré pour une ressource et une action précises. Le service vérifie que ce droit n’a pas été modifié, qu’il concerne bien la bonne ressource et qu’il n’est pas expiré.

Le droit peut être un code aléatoire conservé par le serveur, ou un ensemble de données accompagné d’une signature secrète. La signature permet de détecter toute modification. Les données doivent indiquer au moins la ressource, l’action autorisée et la date de fin. Un droit de lecture ne doit pas devenir un droit de suppression parce qu’un champ a été changé.

Le système doit décider dès le départ comment retirer un droit. Si le serveur ne conserve aucune information sur les droits délivrés, il ne peut généralement pas retirer un droit précis avant sa date de fin. Il peut seulement attendre l’expiration ou changer la clé de signature, ce qui invalide beaucoup de droits à la fois.

Le principal danger est la copie. Toute personne ou programme qui obtient le droit peut souvent l’utiliser. Il faut donc limiter sa durée, éviter de le mettre dans les journaux, le transmettre par un canal chiffré et donner uniquement les permissions nécessaires.

À lire aussi

Pages voisines

: les deux pages se citent l’une l’autre.