我已经阅读了关于在web.config中保护敏感数据的MSDN blog帖子,方法是加密内容并在Azure上设置证书,以便回读它们。
但是,Visual Studio Azure部署项目中的“服务配置”.cscfg文件中存在绝密数据。我们在此存储连接字符串和其他敏感数据,以便测试系统(也在Azure上)可以定向到等效的测试后端服务。
使用CloudConfigurationManager(例如.GetSetting(“AwsSecretKey”))访问此数据,而不是博客文章中讨论的WebConfigurationManager。
是否可以以类似的方式保护这些数据?重要的是我们在测试和生产中使用不同的AWS和SQL连接字符串,并且生产密钥对我和其他开发人员都是隐藏的。
答案 0 :(得分:4)
是的,我们使用在部署配置中上传的x509证书来执行此操作。但是,这些设置仅与保护私钥的策略/过程一样安全!以下是我们在Azure角色中用于解密ServiceConfiguration中的值的代码:
/// <summary>Wrapper that will wrap all of our config based settings.</summary>
public static class GetSettings
{
private static object _locker = new object();
/// <summary>locked dictionary that caches our settings as we look them up. Read access is ok but write access should be limited to only within a lock</summary>
private static Dictionary<string, string> _settingValues = new Dictionary<string, string>();
/// <summary>look up a given setting, first from the locally cached values, then from the environment settings, then from app settings. This handles caching those values in a static dictionary.</summary>
/// <param name="settingsKey"></param>
/// <returns></returns>
public static string Lookup(string settingsKey, bool decrypt = false)
{
// have we loaded the setting value?
if (!_settingValues.ContainsKey(settingsKey))
{
// lock our locker, no one else can get a lock on this now
lock (_locker)
{
// now that we're alone, check again to see if someone else loaded the setting after we initially checked it
// if no one has loaded it yet, still, we know we're the only one thats goin to load it because we have a lock
// and they will check again before they load the value
if (!_settingValues.ContainsKey(settingsKey))
{
var lookedUpValue = "";
// lookedUpValue = RoleEnvironment.IsAvailable ? RoleEnvironment.GetConfigurationSettingValue(settingsKey) : ConfigurationManager.AppSettings[settingsKey];
// CloudConfigurationManager.GetSetting added in 1.7 - if in Role, get from ServiceConfig else get from web config.
lookedUpValue = CloudConfigurationManager.GetSetting(settingsKey);
if (decrypt)
lookedUpValue = Decrypt(lookedUpValue);
_settingValues[settingsKey] = lookedUpValue;
}
}
}
return _settingValues[settingsKey];
}
private static string Decrypt(string setting)
{
var thumb = Lookup("DTSettings.CertificateThumbprint");
X509Store store = null;
try
{
store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates.Cast<X509Certificate2>().Single(xc => xc.Thumbprint == thumb);
var rsaProvider = (RSACryptoServiceProvider)cert.PrivateKey;
return Encoding.ASCII.GetString(rsaProvider.Decrypt(Convert.FromBase64String(setting), false));
}
finally
{
if (store != null)
store.Close();
}
}
}
然后,您可以利用RoleEnvironment.IsAvailable
仅解密模拟器或部署环境中的值,从而使用未加密的App设置和key =“MyConnectionString”在本地IIS中运行Web角色,以进行本地调试(无需模拟器) :
ContextConnectionString = GetSettings.Lookup("MyConnectionString", decrypt: RoleEnvironment.IsAvailable);
然后,为了完成该示例,我们使用以下代码创建了一个简单的WinForsm应用程序,以使用给定的证书加密/解密该值。我们的生产团队维护对生产证书的访问权限,并使用WinForms App加密必要的值。然后,他们为DEV团队提供加密值。你可以找到full working copy of the solution here。这是WinForms应用程序的主要代码:
private void btnEncrypt_Click(object sender, EventArgs e)
{
var thumb = tbThumbprint.Text.Trim();
var valueToEncrypt = Encoding.ASCII.GetBytes(tbValue.Text.Trim());
var store = new X509Store(StoreName.My, rbLocalmachine.Checked ? StoreLocation.LocalMachine : StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates.Cast<X509Certificate2>().Single(xc => xc.Thumbprint == thumb);
var rsaProvider = (RSACryptoServiceProvider)cert.PublicKey.Key;
var cypher = rsaProvider.Encrypt(valueToEncrypt, false);
tbEncryptedValue.Text = Convert.ToBase64String(cypher);
store.Close();
btnCopy.Enabled = true;
}
private void btnDecrypt_Click(object sender, EventArgs e)
{
var thumb = tbThumbprint.Text.Trim();
var valueToDecrypt = tbEncryptedValue.Text.Trim();
var store = new X509Store(StoreName.My, rbLocalmachine.Checked ? StoreLocation.LocalMachine : StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates.Cast<X509Certificate2>().Single(xc => xc.Thumbprint == thumb);
var rsaProvider = (RSACryptoServiceProvider)cert.PrivateKey;
tbDecryptedValue.Text = Encoding.ASCII.GetString(rsaProvider.Decrypt(Convert.FromBase64String(valueToDecrypt), false));
}
private void btnCopy_Click(object sender, EventArgs e)
{
Clipboard.SetText(tbEncryptedValue.Text);
}