Skip to content

FR Security

yannds edited this page Jul 5, 2026 · 2 revisions

08 - Sécurité

Kengela est un socle de sécurité : sa propre posture doit être prouvée, pas affirmée. Cette page résume la doctrine Zero Trust et les contrôles vérifiés par la suite de tests adverses.

Posture Zero Trust (les invariants)

Invariant Où il est appliqué
Deny-by-default PDP (RbacDecisionPoint / LayeredDecisionPoint), guard NestJS (route non annotée = 403)
Fail-closed condition CEL inévaluable → deny ; session expirée → null ; tenant non résoluble → refus ; narrowing d'union illisible → écarté
Isolation multi-tenant au cœur tenantScopedRelation() : cross-tenant → relation none ; seul un grant global franchit
Anti-staleness grants rechargés à chaque check (un droit révoqué cesse d'agir immédiatement)
Timing-safe verify toujours effectué (hash leurre), pas de court-circuit cross-tenant (anti-énumération)
Crypto authentifié AES-256-GCM, clé par tenant (HKDF) et par sujet ; toute altération → rejet
Anti-ReDoS matches interdit dans CEL ; regex bornées dans iam-mapping ; filtres SCIM bornés
Observabilité DecisionLogSink (autorisation), AuditSink (métier/sécurité), PiiAccessLogSink (RGPD art. 30)

Contrôles vérifiés

Scénario attaqué Contrôle prouvé
Escalade par portée subtree ne couvre pas tenant ; grant expiré inopérant ; seul global franchit un tenant
Fail-open / deny-wins relation none sans grant global = deny ; deny explicite gagne ; condition qui lève = deny
Sandbox CEL accès process/globalThis/__proto__ → throw ; non-booléen → throw ; variable absente → throw
Énumération par timing compare leurre toujours effectué (email inconnu, compte inactif) ; cross-tenant sans court-circuit
AES-256-GCM iv/tag/ciphertext altéré → rejet ; tronqué → rejet ; mauvaise clé tenant → rejet ; nonce unique
Crypto-shredding après eraseSubject, PII illisible ; clé d'un autre sujet ne déchiffre pas
Rejeu MFA challengeId one-shot ; verify sans secret = false ; challengeId forgé = false
SCIM filtres bornés ; injection non interprétée ; unicité 409 ; delete = désactivation ; 404 cross-tenant
Mapping IdP safe-regex anti-ReDoS ; règle vide ne matche jamais ; SAML sans groupe ne fabrique aucun rôle
better-auth session absente → null ; tenant non résoluble → null ; roles/mfa jamais hérités du payload
LDAP filtre verbatim ; unbind garanti même en erreur ; plafond max appliqué ; secret non journalisé
Sessions rotation invalide l'ancien token ; revokeAllForUser effectif ; token 256 bits sans collision
Guard NestJS deny-by-default (403) ; principal absent = 401 ; précédence handler > classe

Cartographie de conformité

Cadre Couverture
OWASP ASVS v4 V2 authn (argon2id, anti-énumération), V3 session (expiration fail-closed, rotation, 256 bits), V4 access control (deny-by-default, tenantScopedRelation, deny-wins), V6 crypto (AES-256-GCM par tenant/sujet), V7 logging (decision log), V9 data protection (pii, FieldCipherPort)
NIST SP 800-63B hashing argon2id memory-hard + needsRehash ; verifier temps constant ; MFA TOTP (RFC 6238) secret chiffré + défi one-shot
RGPD minimisation, effacement art. 17 (crypto-shredding), journal d'accès art. 30, rétention, chiffrement at-rest, isolation cryptographique inter-tenant
SCIM RFC 7643/7644 + validateur Microsoft Entra (schéma, filtre eq borné, PATCH, unicité 409, déprovisionnement = désactivation, isolation tenant)

Signaler une vulnérabilité

Kengela est sous licence Apache-2.0. Pour un signalement responsable, ouvrez un contact privé avec le mainteneur plutôt qu'une issue publique tant que le correctif n'est pas disponible.

Clone this wiki locally