【问题标题】:Attempt to set permissions on a KeyContainer in C# is having no effect尝试在 C# 中对 KeyContainer 设置权限无效
【发布时间】:2010-06-29 16:36:27
【问题描述】:

我正在使用以下代码尝试以编程方式允许 NetworkService 帐户访问密钥:

var RSA = new RSACryptoServiceProvider(
   new CspParameters() { 
     KeyContainerName = "MyEncryptionKey", 
     Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore 
});

RSA.CspKeyContainerInfo.CryptoKeySecurity.AddAccessRule(
  new System.Security.AccessControl.CryptoKeyAccessRule(
    new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null),
    CryptoKeyRights.GenericAll,
    AccessControlType.Allow
  )
);

此代码运行无误,但对密钥容器的权限没有影响。

但是,使用命令行工具 aspnet_regiis 来做同样的事情,效果很好:

aspnet_regiis -pa "MyEncryptionKey" "NetworkService"

我正在以完全管理员权限运行 - 如果我不以这些权限运行,则会引发异常。我也以最初创建密钥的用户身份运行。

密钥容器始终具有以下访问规则:

S-1-5-18         -> LocalSystem
S-1-5-32-544     -> Administrators
S-1-5-5-0-135377 -> MyUser

使用 aspnet_regiis,SID,S-1-5-20 被添加到此列表中。我无法通过代码影响它。

我已尝试从 sid 以字符串格式创建安全标识符,以及使用 SetAccessRule 而不是 AddAccessRule。

任何想法如何从代码中实际影响此 ACL 列表?

【问题讨论】:

    标签: c# .net cryptography rsacryptoserviceprovider dpapi


    【解决方案1】:

    你似乎没有在调用 Persist。您对 CryptoKeySecurity 所做的更改实际上不会立即保存。您需要使用Persist(...) 方法之一来实际保存更改。

    NativeObjectSecurity.Persist Method (String, AccessControlSections)

    似乎这些 API 遵循一种相当复杂的修改方法。您需要先创建一个 CspParameters,应用必要的更改,然后从这些参数构造提供程序。构造调用容器上的更新。

    var params = new CspParameters
    {
         KeyContainerName = "MyEncryptionKey", 
         Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore    
    };
    
    params.CryptoKeySecurity.AddAccessRule(
      new System.Security.AccessControl.CryptoKeyAccessRule(
        new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null),
        CryptoKeyRights.GenericAll,
        AccessControlType.Allow
      )
    );
    
    var RSA = new RSACryptoServiceProvider(params);
    

    【讨论】:

    • 遗憾的是所有 Persist 方法都受到保护。
    • 看起来您需要在使用 CspParameters 创建提供程序之前修改安全性。 CspParameters 在传递给 RSACryptoServiceProvider 时会调用持久化。构建 API 的方式非常奇怪,但根据文档,这似乎就是它的工作方式。答案已更新以反映。
    • 这让我走上了正轨。上面使用的 CryptoKeySecurity 属性为空,因此抛出。您可以创建一个新的,但它会清除任何已经存在的权限(这是它的第一个实际效果,所以现在我被锁定在我的主密钥库之外;)。但是...如果您从密钥库中获取密钥,则通过复制 RSA.CspKeyContainerInfo 中的值(包括提供者名称和类型、容器名称和 CryptoKeySecurity)来创建一个新的 CspParamters,然后您可以对其进行修改,创建另一个 RSA 密钥使用 csp 参数的对象,瞧,一切都完成了。简单...?
    • 如果您确实在使用机器密钥,添加 UseMachineKeyStore 标志也有帮助。
    【解决方案2】:

    我只是想正式确定 Jim T 在 cmets 中所说的话,因为它对我有用。

    //Read the current settings
    CspParameters csp = new CspParameters(PROVIDER_RSA_FULL)
    {
        KeyContainerName = container,
        Flags = CspProviderFlags.NoPrompt | CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey
    };
    //Retrieve Current Settings
    using (var rsa = new RSACryptoServiceProvider(csp))
    {
        var ci = rsa.CspKeyContainerInfo;
    
        //Create new settings and copy values over
        CspParameters csp2 = new CspParameters(PROVIDER_RSA_FULL)
        {
            KeyContainerName = container,
            Flags = CspProviderFlags.NoPrompt | CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey,
            CryptoKeySecurity = ci.CryptoKeySecurity,
            ProviderName = ci.ProviderName,
            ProviderType = ci.ProviderType
        };
        //Add Permissions
        csp2.CryptoKeySecurity.AddAccessRule(new CryptoKeyAccessRule(securityIdentifier, CryptoKeyRights.FullControl, AccessControlType.Allow));
    
        //Save settings
        using (var rsa2 = new RSACryptoServiceProvider(csp2))
        {
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-01-06
      • 1970-01-01
      • 2011-11-27
      • 2012-07-31
      • 1970-01-01
      • 1970-01-01
      • 2018-03-17
      • 2017-06-29
      • 1970-01-01
      相关资源
      最近更新 更多