2

我们在 Azure 上的两个 Web 应用程序上部署了一个网站:一个生产版本和一个预生产版本。

该网站在特定时间使用以下代码创建一个容器来托管 RSA 密钥:

// -----------------------------
// Part 1 : Initialize csp params
// -----------------------------
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "OurKeyContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";

// --------------------------------------------------
// Part 2 : A try to set folder access rights to "everyone"
// --------------------------------------------------
// http://whowish-programming.blogspot.fr/2010/10/systemsecuritycryptographycryptographic.html
// http://stackoverflow.com/questions/5013881/c-sharp-how-do-i-get-the-everybody-user
var sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
var rule = new CryptoKeyAccessRule(sid, CryptoKeyRights.FullControl, AccessControlType.Allow);
cspParams.CryptoKeySecurity = new CryptoKeySecurity();
cspParams.CryptoKeySecurity.SetAccessRule(rule);

return new RSACryptoServiceProvider(cspParams);

问题是此代码仅适用于其中一个网站,即实际首次启动的网站。第二个抛出 CryptographicException “对象已存在”。

谷歌搜索后,该问题似乎是由执行网站的用户无权访问密钥容器引起的,但不幸的是,推荐的修复(在我们上面的代码的第 2 部分中实现)不起作用..

有什么想法或建议吗?

谢谢

里亚纳

4

1 回答 1

2

我认为问题在于您基本上是在尝试两次创建具有相同名称的机器范围的容器。我假设pre-prodprod环境在同一台机器上,也许是您的应用服务中的部署槽?我至少可以用这个设置复制你的问题。我猜还有一些其他设置可能会产生相同的情况,但这是最有可能的。

您可以在此设置中更改三项将产生不同结果的内容:

  • 授予访问权限的身份
  • 集装箱商店
  • 容器名称

对于身份,我们可以使用Everyone(如您所尝试的那样)或者Current我们可以从 WindowsIdentity 获得

    private IdentityReference GetWindowsIdentity()
    {
        return System.Security.Principal.WindowsIdentity.GetCurrent().User;
    }

    private IdentityReference GetEveryoneIdentity()
    {
        return new SecurityIdentifier(WellKnownSidType.WorldSid, null);
    }

容器存储可以是当前用户,也可以machine wide只是当前用户

// machine wide store
var cspParams = new CspParameters(PROVIDER_RSA_FULL)
{
    ...
    Flags = CspProviderFlags.UseMachineKeyStore;
    ...
};

// default store
var cspParams = new CspParameters(PROVIDER_RSA_FULL)
{
    ...
    Flags = CspProviderFlags.UseDefaultKeyContainer;
    ...
};

对于商店名称,我们可以选择一些东西,在您的情况下,您可以选择相同的名称,但我们也可以为身份设置一些独特的东西

    KeyContainerName = "OurKeyContainer",

    KeyContainerName = $"OurKeyContainer-{identity}",

不同的组合会产生不同的结果:

每个人的身份,机器范围的存储,相同的容器名称在其中一个插槽上失败System.Security.Cryptography.CryptographicException: Object already exists.

每个人的身份,机器范围的商店,每个身份的容器都可以

每个人的身份、用户存储、相同的容器名称在两个插槽上都失败System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

每个人的身份、用户存储、每个身份的容器OK

当前身份,机器范围的存储,相同的容器名称在其中一个插槽上失败System.Security.Cryptography.CryptographicException: Object already exists.

当前身份,机器范围的存储,每个身份的容器OK

Current identity, user store, same container name Fails on both of the slots with System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

Current identity, user store, container per identity Fails on both of the slots with System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

So, to summarize, changing the name of the container to include something that is unique for the environment will fix the problem. It doesn't have to be the identity (but you will get one identity per App Service you are running on a machine so it is fairly safe), it could be the name of the environment if you set it as an ENVIRONMENT VARIABLE in your App Service and make sure it is set to pre-prod and prod respectively.

Here is the playaround code to test it

于 2017-01-30T07:54:51.200 回答