Comment un assembly CLR créé avec PERMISSION_SET =SAFE peut-il accéder à des ressources système externes, appeler du code non géré et acquérir des privilèges d'administrateur système ?
Cela est dû aux modifications de sécurité apportées au .NET Framework, à partir de la version 4.5 (je crois).
La documentation MSDN pour Code Access Security Basics indique :
Le .NET Framework fournit un mécanisme pour l'application de différents niveaux de confiance sur différents codes exécutés dans la même application, appelé Code Access Security (CAS). La sécurité d'accès au code dans .NET Framework ne doit pas être utilisée comme un mécanisme pour appliquer des limites de sécurité basées sur l'origine du code ou d'autres aspects d'identité. Nous mettons à jour nos directives pour refléter que la sécurité d'accès au code et le code transparent de sécurité ne seront pas pris en charge en tant que limite de sécurité avec un code partiellement fiable, en particulier un code d'origine inconnue. Nous vous déconseillons de charger et d'exécuter du code d'origine inconnue sans mettre en place des mesures de sécurité alternatives.
Et pointe ensuite vers la page des modifications de sécurité dans le .NET Framework qui indique :
Le changement le plus important apporté à la sécurité dans .NET Framework 4.5 concerne la dénomination forte.
Ce qui pointe ensuite vers la documentation de Enhanced Strong Naming qui indique :
Les clés de nom fort se composent d'une clé de signature et d'une clé d'identité. L'assemblage est signé avec la clé de signature et est identifié par la clé d'identité. Avant le .NET Framework 4.5, ces deux clés étaient identiques. À partir du .NET Framework 4.5, la clé d'identité reste la même que dans les versions antérieures du .NET Framework, mais la clé de signature est améliorée avec un algorithme de hachage plus puissant. De plus, la clé de signature est signée avec la clé d'identité pour créer une contre-signature.
ÉGALEMENT, la documentation relative aux directives de codage sécurisé indique :
La sécurité d'accès au code et le code transparent de sécurité ne seront pas pris en charge en tant que limite de sécurité avec un code partiellement fiable. Nous vous déconseillons de charger et d'exécuter du code d'origine inconnue sans mettre en place des mesures de sécurité alternatives...
Ainsi, le modèle de sécurité pour .NET a changé il y a des années, mais SQL Server (jusqu'à SQL Server 2017) a été autorisé à continuer à utiliser l'ancien modèle de sécurité. Il semble qu'à partir de SQL Server 2017, la décision ait été prise de ne plus prendre en charge l'ancien modèle de sécurité.
Je soupçonne que l'autorisation de l'ancien modèle de sécurité était :
-
empêcher SQL Server (au moins les fonctionnalités/composants liés au CLR) d'être basé sur les nouvelles versions de .NET Framework, et
-
responsable de la suppression brutale de SQLCLR en tant que fonctionnalité prise en charge d'Azure SQL Database (la prise en charge a été ajoutée fin 2014 avec le lancement de la v12, mais a ensuite été entièrement supprimée à compter du 15 avril 2016).
Donc, oui, ça craint un peu. Cela signifie (du moins pour le moment) qu'il faut d'abord créer un certificat ou une clé asymétrique (qui a été utilisé pour signer tous les assemblages à charger) dans [master]
pour ensuite créer une connexion à partir de puis accorder UNSAFE ASSEMBLY
à cette connexion. C'est la même séquence d'événements que l'on doit faire lors du chargement de EXTERNAL_ACCESS
et UNSAFE
Les assemblages, mais maintenant, malheureusement, doivent être faits pour même SAFE
Assemblages.
Il n'existe actuellement aucun mécanisme pour gérer cela de manière complètement portable (c'est-à-dire sans compter sur des fichiers externes) et ne peut pas être géré par Visual Studio / SSDT sans intervention manuelle. C'était un peu déjà le cas, mais au moins il était possible de créer une configuration pour gérer cela de manière complètement portable (c'est-à-dire entièrement contenue dans un script .sql) :veuillez consulter Stairway to SQLCLR Level 7 :Development and Security pour plus de détails (c'est un article que j'ai écrit).
Il est possible de créer un certificat à partir d'octets hexadécimaux (c'est-à-dire FROM BINARY = 0x...
) mais cela ne fonctionne pas avec Visual Studio (qui s'appuie sur MSBuild) / SSDT car l'utilisation du certificat nécessite l'utilisation de signtool
et MSBuild utilise sn
.
Pour que cela soit rendu réalisable de sorte que le processus de publication Visual Studio / MSBuild / SSDT fonctionne (ce qui signifierait à son tour que n'importe qui pourrait créer un script .sql complètement autonome capable de créer la clé asymétrique sans s'appuyer sur un fichier externe), le CREATE ASYMMETRIC KEY
La commande doit être améliorée pour permettre sa création à partir d'une chaîne binaire. J'ai fait cette suggestion sur Microsoft Connect - Autoriser la création d'une clé asymétrique à partir d'une chaîne d'octets hexadécimaux binaires, tout comme CREATE CERTIFICATE - veuillez donc la prendre en charge :-).
Alternativement (pour le moment, jusqu'à ce que MS crée, espérons-le, une meilleure méthode, comme mes suggestions de clé asymétrique), vous pouvez essayer l'une des deux techniques que je décris dans les articles de blog suivants (les deux fonctionnent entièrement avec SSDT) :
- SQLCLR par rapport à SQL Server 2017, partie 2 :"Sécurité stricte du CLR" – Solution 1
- SQLCLR par rapport à SQL Server 2017, partie 3 :"Sécurité stricte du CLR" – Solution 2
En tant que dernier resort, vous pouvez envisager l'approche suivante :
-
TEMPORAIREMENT définir le
[master]
Base de données surTRUSTWORTHY ON
Pour l'étape suivante (c'est-à-dire
CREATE ASSEMBLY
) pour s'exécuter avec succès, le login qui est le propriétaire de la base de données (c'est-à-dire le même SID utilisé par le[dbo]
Utilisateur de[master]
) doit avoir leUNSAFE ASSEMBLY
autorisation. Si[master]
appartient àsa
ou tout autre administrateur système, il dispose de toutes les autorisations et cette exigence est satisfaite. Mais, si[master]
appartient à une connexion à faibles privilèges (une "meilleure pratique"), vous devrez alors exécuter l'instruction suivante pour que leCREATE ASSEMBLY
fonctionner lorsqueTRUSTWORTHY
estON
:EXEC (N'USE [master]; GRANT UNSAFE ASSEMBLY TO [{DB_Owner_Login}];');
- Créer l'assemblage dans
[master]
- Créer la clé asymétrique à partir de l'assemblage
- Laisser tomber l'assemblage
- définissez le
[master]
Base de données àTRUSTWORTHY OFF
- Créer la connexion à partir de la clé asymétrique
- Accorder
UNSAFE ASSEMBLY
à cette connexion (cela remplace la nécessité pour la base de données où l'assembly est chargé d'être défini surTRUSTWORTHY ON
et pour son propriétaire Connectez-vous pour avoir leUNSAFE ASSEMBLY
autorisation).
Veuillez noter que je n'ai pas inclure la nouvelle fonctionnalité "Trusted Assembly" en option ici. La raison pour laquelle il n'a pas été mentionné est qu'il a beaucoup plus de défauts que d'avantages, sans parler du fait qu'il est tout à fait inutile en premier lieu étant donné que la fonctionnalité existante gérait déjà la situation que les "assemblages de confiance" étaient censés résoudre. Pour plus de détails à ce sujet et une démonstration de la bonne façon de gérer les assemblages existants non signés, veuillez consulter :SQLCLR vs SQL Server 2017, partie 4 : « Assemblages de confiance » – La déception.