Partager via


Recommandations en matière de sécurité ACS

Mise à jour : 19 juin 2015

S’applique à : Azure

S'applique à

  • Microsoft Azure Active Directory Access Control (également appelé Access Control Service ou ACS)

  • Windows Identity Foundation (WIF)

Résumé

Cette rubrique consolide les instructions de sécurité pour ACS. Utilisez-les pour améliorer la qualité de votre implémentation du point de vue de la sécurité. Vous pouvez utiliser ces recommandations lors de l'examen de l'architecture de votre application, lors de l'examen du code et de l'enregistrement des bogues de sécurité et lors de l'examen du déploiement de production. Ces instructions vous font référence pour plus d’informations sur l’utilisation des étapes prescriptives pour accomplir une tâche spécifique et pour en savoir plus sur une fonctionnalité ou une fonction particulière d’ACS.

Objectifs

  • Résolvez les problèmes de sécurité liés au code et à la configuration d’une application dans le contexte d’ACS.

  • Résoudre les problèmes de sécurité liés aux configurations ACS.

  • Résolvez les problèmes de sécurité liés aux déploiements Azure dans le contexte d’ACS.

Vous trouverez ci-dessous des recommandations de sécurité relatives au code et à la configuration de votre application.

  • Affectez la valeur True à la fonctionnalité de détection de relecture (DetectReplayedTokens).

  • Affectez la valeur True à l'attribut requireHttps de wsFederation.

  • Affectez la valeur True à l'attribut requireSsl de cookieHandler.

  • Définissez la valeur agressive pour l'attribut de durée de vie de sessionTokenRequirement.

  • Énumérez les services STS approuvés (émetteurs de jetons) dans issuerNameRegistry.

  • Définissez l'étendue des jetons qui doivent être acceptés par votre application à l'aide de audienceUri.

Affecter la valeur True à la fonctionnalité de détection de relecture (DetectReplayedTokens)

WIF possède un cache de détection de relecture spécifiquement pour les jetons STS. Il s'agit simplement d'un cache contenant les jetons STS utilisés précédemment. Quand le client s'authentifie pour la première fois auprès de la partie de confiance à l'aide du jeton STS, il reçoit un jeton de sécurité de session qu'il utilise pour s'authentifier auprès de la partie de confiance pour toute demande supplémentaire. Cette opération s'effectue par l'intermédiaire du protocole SSL (Secure Sockets Layer) pour que le jeton de sécurité de cession ne puisse pas être volé. Si un client ou un agresseur essaie de s'authentifier auprès de la partie de confiance avec un jeton STS que le client a déjà utilisé, la partie de confiance peut rechercher le jeton STS dans le cache de relecture et refuser la demande.

Ce cache ne garantit pas qu'un jeton ne puisse jamais être relu. Il effectue une détection de type « meilleur effort » basée sur la taille du cache, le délai d'expiration du jeton STS et le taux de demandes d'authentification uniques reçues par la partie de confiance. Nous vous recommandons vivement de définir la taille de cache et le délai d'expiration de jeton STS de votre partie de confiance de manière à obtenir un bon équilibre entre performances et sécurité.

Exemple :

<securityTokenHandlers>
  <securityTokenHandlerConfiguration>
    <tokenReplayDetection enabled="true" capacity="1000" expirationPeriod="500"/>
  </securityTokenHandlerConfiguration>
</securityTokenHandlers>

Remarque

L'utilisation de cette fonctionnalité introduit une affinité de serveur pouvant entraîner des problèmes d'extensibilité dans les environnements à équilibrage de la charge, y compris Azure. Pour éviter ces problèmes, vous pouvez implémenter votre propre détection de relecture de jeton à l'aide d'une classe abstraite de base Microsoft.IdentityModel.Tokens.TokenReplayCache et y faire référence dans le fichier de configuration, avec du code semblable au suivant.

<system.identityModel>
  <identityConfiguration>
    <tokenReplayDetection>
      <replayCache type='FQTN of your type' />
    </tokenReplayDetection>
  </identityConfiguration>
</system.identityModel>

Affecter la valeur True à l'attribut requireHttps de wsFederation

L'attribut requireHttps détermine si le module redirige uniquement une URL sécurisée pour le service STS. Par défaut, il a la valeur « True ». Cela permet de sécuriser les communications avec le service STS sur le trafic HTTPS/SSL en clair et d'atténuer les risques de détection de jetons et d'informations d'identification sur le réseau.

Exemple :

<federatedAuthentication>
  <wsFederation
        passiveRedirectEnabled="true"
        issuer="http://STS URL GOES HERE/"
        realm="http://RP REALM GOES HERE/"
        requireHttps="ture" />
  <cookieHandler requireSsl="true" />
</federatedAuthentication>

Affecter la valeur True à l'attribut requireSsl de cookieHandler

Cette valeur est booléenne. Elle est « False » par défaut. L'attribut requireSsl détermine si l'indicateur « Sécurisé » est émis pour tout cookie écrit. Si cette valeur est définie, les cookies de session de connexion sont disponibles uniquement sur le protocole HTTPS. Cela empêche l'envoi de cookies de session sur du trafic en clair et atténue le risque de détection du jeton sur le réseau.

Exemple :

<federatedAuthentication>
  <wsFederation
        passiveRedirectEnabled="true"
        issuer="http://STS URL GOES HERE/"
        realm="http://RP REALM GOES HERE/"
        requireHttps="ture" />
  <cookieHandler requireSsl="true" />
</federatedAuthentication>

Définir la valeur agressive pour l'attribut de durée de vie de sessionTokenRequirement

Vous pouvez exiger que les jetons soient émis avec des limites de durée de vie agressives. Un agresseur disposera ainsi de moins de temps pour relire le jeton en cas de vol.

Exemple :

<add type="Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler, Microsoft.IdentityModel">
  <sessionTokenRequirement securityTokenCacheType="Microsoft.IdentityModel.MruSecurityTokenCache, Microsoft.IdentityModel"
                           saveBootstrapTokens="true"
                           securityTokenCacheSize="500"
                           useWindowsTokenService="false"
                           lifetime="10:00" />
</add>

Énumérer les services STS approuvés (émetteurs de jetons) dans issuerNameRegistry

Tous les jetons d'émetteurs sont validés à l'aide de l'élément IssuerNameRegistry. IssuerNameRegistry a pour fonction de mapper le jeton d'émetteur à un nom de chaîne. Si la validation échoue, le jeton n'est pas accepté. Cela atténue le risque que des jetons non approuvés soient acceptés. Tout type personnalisé peut être inscrit à l’aide de l’attribut de type de l’élément <issuerNameRegistry> . L’émetteurNameRegistry <> peut avoir un élément enfant qui servira de configuration personnalisée à l’IssuerNameRegistry. Un type IssuerNameRegistry est fourni par défaut : ConfigurationBasedIssuerNameRegistry. Vous pouvez l'utiliser pour configurer un ensemble de certificats d'émetteurs approuvés dans la configuration. Ce type nécessite un élément <de configuration enfant trustedIssuers où les certificats d’émetteur approuvés sont configurés> . <la configuration trustedIssuers> ajoute des certificats approuvés à l’aide du formulaire codé ASN.1 de l’empreinte numérique du certificat.

Exemple :

<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel">
  <trustedIssuers>
    <add thumbprint="97249e1a5fa6bee5e515b82111ef524a4c9158de" name="contoso.com" />
    <remove thumbprint="97249e1a5fa6bee5e515b82111ef524a4c9158de" />
    <clear/>
  </trustedIssuers>
</issuerNameRegistry>

Définir l'étendue des jetons pour votre application uniquement à l'aide d'audienceUri

<audienceUris> spécifie l’ensemble d’URI acceptables pour identifier cette partie de confiance. Les jetons ne sont pas acceptés à moins d'avoir pour étendue l'un des URI d'audience autorisés. Cela atténue le risque de relecture de jetons valides ayant été émis pour d'autres parties de confiance. Par défaut, aucun URI n'est ajouté à cette collection. Le SecurityTokenHandler pour les types de jetons SAML 1.1 et SAML 2.0 utilise les valeurs contenues dans cette collection pour configurer d'éventuelles restrictions applicables aux URI d'audience autorisés dans les objets SamlSecurityTokenRequirement.

Exemple :

<audienceUris>
  <clear/>
  <add value="http://www.example.com/myapp/" />
  <remove value="http://www.example.com/myapp/" />
</audienceUris>

Voici les instructions de sécurité relatives à la configuration du portail de gestion ACS.

  • Définir une expiration agressive pour les jetons STS

  • Fournir une validation des données adéquate lors de l'utilisation de la fonctionnalité d'URL d'erreur

  • Chiffrer les jetons pour les scénarios à confidentialité élevée

Définir une expiration agressive pour les jetons STS

L'attribut de durée de vie de jeton contrôle la durée de vie du jeton. Il est spécifié lorsque vous créez ou configurez la partie de confiance à l’aide du portail ACS ou du service de gestion. Vous pouvez utiliser la propriété Durée de vie du jeton pour spécifier la durée pendant laquelle un jeton de sécurité émis par ACS à l’application de partie de confiance reste valide. Par défaut, dans ACS, cette valeur est définie sur 10 minutes (600 secondes). Dans ACS, cette valeur doit être supérieure à zéro, mais inférieure ou égale à 24 heures (86400 secondes).

Fournir une validation des données adéquate lors de l'utilisation de la fonctionnalité d'URL d'erreur

Vous pouvez utiliser l’URL d’erreur pour spécifier une URL vers laquelle ACS redirige les utilisateurs si une erreur se produit pendant le processus de connexion. Il peut s’agir d’une page personnalisée hébergée sur l’application de partie de confiance, par exemple http://www.fabrikam.com/billing/error.aspx. Dans le cadre de la redirection, ACS fournit des détails sur l’erreur à l’application de partie de confiance en tant que paramètre d’URL HTTP encodé JSON. La page d'erreur personnalisée peut être conçue pour consommer les informations d'erreur encodées JSON afin d'afficher le message d'erreur reçu ou du texte d'aide statique. Si la page nécessite une autorisation, le résultat est une boucle de redirection infinie dans un cas où ACS essaie d’y accéder et envoie l’erreur codée JSON. Elle doit donc être configurée pour un accès anonyme. Étant donné que la page est accessible de manière anonyme et peut inclure du code qui renvoie du HTML ou qui écrit des données dans la base de données, vous devez prendre les mesures nécessaires pour éviter les scripts de site à site et les attaques par injection SQL.

Chiffrer les jetons pour les scénarios à confidentialité élevée

Pour les scénarios à confidentialité élevée pour la fédération passive, il peut-être préférable de chiffrer les jetons. En savoir plus sur le chiffrement et le déchiffrement du jeton dans la rubrique Certificats et clés .

Voici des considérations relatives à la sécurité liées aux applications qui utilisent ACS et qui sont déployées sur Azure.

  • Chiffrer les cookies avec RSA

Chiffrer les cookies avec RSA

Dans Azure, le mécanisme de chiffrement des cookies par défaut (qui utilise des interfaces DPAPI [Data Protection Application Programming Interfaces]) ne convient pas car chaque instance possède une clé différente. Cela signifie qu'un cookie créé par une instance de rôle web ne serait pas lisible par une autre instance de rôle web. Cela pourrait entraîner des défaillances de service, et par conséquent des dénis de service. Voici le message d'erreur qui s'affiche si vous utilisez le mécanisme de chiffrement des cookies par défaut :

[CryptographicException: Key not valid for use in specified state.
]
System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope) +577
Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded) +80
[InvalidOperationException: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API (see inner exception for details). If you are using IIS 7.5, this could be due to the loadUserProfile setting on the Application Pool being set to false. ]
Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded) +433
Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound) +189
Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver) +862
Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver) +109
Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie) +356
Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken) +123
Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) +61
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +270

Pour résoudre ce problème, utilisez un mécanisme de chiffrement des cookies qui utilise une clé partagée par toutes les instances de rôle web. Le code suivant montre comment remplacer l'objet SessionSecurityHandler par défaut et le configurer pour utiliser la classe RsaEncryptionCookieTransform.

private void OnServiceConfigurationCreated(object sender, 
    ServiceConfigurationCreatedEventArgs e)
{
    List<CookieTransform> sessionTransforms =
        new List<CookieTransform>(
            new CookieTransform[] 
            {
                new DeflateCookieTransform(), 
                new RsaEncryptionCookieTransform(
                    e.ServiceConfiguration.ServiceCertificate),
                new RsaSignatureCookieTransform(
                    e.ServiceConfiguration.ServiceCertificate)  
            });
   SessionSecurityTokenHandler sessionHandler = 
    new
     SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());

    e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(
        sessionHandler);
}

void Application_Start(object sender, EventArgs e)
{
    FederatedAuthentication.ServiceConfigurationCreated += OnServiceConfigurationCreated;
}

Ressources supplémentaires