在.NetCore中默认使用DataProtection来保护数据,例如Cooike等。一般情况下DataProtection生成的密钥会被加密后存储,例如默认的文件存储

可以看到使用了Windows DPAPI加密。

但是如果更改默认设置例如使用的外部存储如redis则此时密钥默认是不加密的

微软说明如下

警告密钥未加密,这个时候如果redis被破解,系统的密钥也就泄漏了。

微软提供了2个接口IXmlEncryptor,IXmlDecryptor来实现密钥的加密解密,下面使用AES来简单现实,也可以替换为任何加密方式

namespace Microsoft.AspNetCore.DataProtection
{
/// <summary>
/// Extensions for configuring data protection using an <see cref="IDataProtectionBuilder"/>.
/// </summary>
public static class DataProtectionBuilderExtensions
{
/// <summary>
/// Configures keys to be encrypted with AES before being persisted to
/// storage.
/// </summary>
/// <param name="builder">The <see cref="IDataProtectionBuilder"/>.</param>
/// use on the local machine, 'false' if the key should only be decryptable by the current
/// Windows user account.</param>
/// <returns>A reference to the <see cref="IDataProtectionBuilder" /> after this operation has completed.</returns>
public static IDataProtectionBuilder ProtectKeysWithAES(this IDataProtectionBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
} builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(services =>
{
//var loggerFactory = services.GetService<ILoggerFactory>() ?? NullLoggerFactory.Instance;
return new ConfigureOptions<KeyManagementOptions>(options =>
{
options.XmlEncryptor = new AesXmlEncryptor();
});
}); return builder;
}
}
/// <summary>
/// An <see cref="IXmlEncryptor"/> that encrypts XML elements with a Aes encryptor.
/// </summary>
sealed class AesXmlEncryptor : IXmlEncryptor
{
/// <summary>
/// Encrypts the specified <see cref="XElement"/> with a null encryptor, i.e.,
/// by returning the original value of <paramref name="plaintextElement"/> unencrypted.
/// </summary>
/// <param name="plaintextElement">The plaintext to echo back.</param>
/// <returns>
/// An <see cref="EncryptedXmlInfo"/> that contains the null-encrypted value of
/// <paramref name="plaintextElement"/> along with information about how to
/// decrypt it.
/// </returns>
public EncryptedXmlInfo Encrypt(XElement plaintextElement)
{
if (plaintextElement == null)
{
throw new ArgumentNullException(nameof(plaintextElement));
}
// <encryptedKey>
// <!-- This key is encrypted with {provider}. -->
// <value>{base64}</value>
// </encryptedKey> var Jsonxmlstr =JsonConvert.SerializeObject(plaintextElement);
var EncryptedData = EncryptHelper.AESEncrypt(Jsonxmlstr, "b587be32-0420-4eb1-89c6-01bb999e18fe");
var newElement = new XElement("encryptedKey",
new XComment(" This key is encrypted with AES."),
new XElement("value",EncryptedData)); return new EncryptedXmlInfo(newElement, typeof(AesXmlDecryptor));
}
}
/// <summary>
/// An <see cref="IXmlDecryptor"/> that decrypts XML elements with a Aes decryptor.
/// </summary>
sealed class AesXmlDecryptor : IXmlDecryptor
{
/// <summary>
/// Decrypts the specified XML element.
/// </summary>
/// <param name="encryptedElement">An encrypted XML element.</param>
/// <returns>The decrypted form of <paramref name="encryptedElement"/>.</returns>
public XElement Decrypt(XElement encryptedElement)
{
if (encryptedElement == null)
{
throw new ArgumentNullException(nameof(encryptedElement));
} // <encryptedKey>
// <!-- This key is encrypted with {provider}. -->
// <value>{base64}</value>
// </encryptedKey>
var EncryptedData=(string)encryptedElement.Element("value");
var Jsonxmlstr = EncryptHelper.AESDecrypt(EncryptedData, "b587be32-0420-4eb1-89c6-01bb999e18fe"); // Return a clone of the single child node.
return JsonConvert.DeserializeObject<XElement>(Jsonxmlstr);
}
}
#region AES
public class EncryptHelper
{
static readonly byte[] AES_IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
/// <summary>
/// AES加密算法
/// </summary>
/// <param name="encryptString">加密前字符串</param>
/// <param name="keytype">秘钥</param>
/// <returns></returns>
public static string AESEncrypt(string encryptString, string encryptKey)
{
if (string.IsNullOrWhiteSpace(encryptString)) return null;
if (string.IsNullOrWhiteSpace(encryptKey)) return null;
encryptKey = encryptKey.PadRight(, ' ');
byte[] keyBytes = Encoding.UTF8.GetBytes(encryptKey.Substring(, ));
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.Key = keyBytes;
aesAlg.IV = AES_IV;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(encryptString);
}
byte[] bytes = msEncrypt.ToArray();
return Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_');
}
}
}
}
/// <summary>
/// AES解密算法
/// </summary>
/// <param name="decryptString">解密前的字符串</param>
/// <param name="keytype">秘钥</param>
/// <returns></returns>
public static string AESDecrypt(string decryptString, string decryptKey)
{
if (string.IsNullOrWhiteSpace(decryptString)) return null;
decryptString = decryptString.Replace('-', '+').Replace('_', '/');
if (string.IsNullOrWhiteSpace(decryptKey)) return null;
decryptKey = decryptKey.PadRight(, ' ');
byte[] keyBytes = Encoding.UTF8.GetBytes(decryptKey.Substring(, ));
Byte[] inputBytes = Convert.FromBase64String(decryptString);
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.Key = keyBytes;
aesAlg.IV = AES_IV;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream(inputBytes))
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srEncrypt = new StreamReader(csEncrypt))
{
return srEncrypt.ReadToEnd();
}
}
}
}
}
}
#endregion
}

调用也很简单.ProtectKeysWithAES()即可

  services.AddDataProtection().SetApplicationName("DataProtection").PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect(RedisConnection), "DataProtection-Keys").ProtectKeysWithAES();

加密后的密钥如下

注:在生成密钥之前要删除之前的密钥,不然会使用旧密钥而不生成新的密钥直到密钥过期。

对于AES所使用密钥也要进行保护,可以使用第三方密钥存储库如Azure 密钥保管库,或者也可以使用X509证书来来加密。

github  https://github.com/saber-wang/DataProtection

最新文章

  1. Linux基础介绍【第七篇】
  2. Object-C 中各数据类型转换 NSData转NSString,Byte,UIImage
  3. 把浏览器的私有模式添加到VS中
  4. CoreLoation
  5. C语言知识整理(3):内存管理(详细版)
  6. addSubView需要注意的几个点
  7. JS通过ajax动态读取xml文件内容
  8. 《OD大数据实战》Hadoop伪分布式环境搭建
  9. 解决div布局中第一个div的margin-top在浏览器中显示无效果问题。
  10. sqlplus登录、连接命令
  11. c#基础语句——分支语句
  12. const volatile同时限定一个类型int a = 10
  13. 安卓学习笔记--已root设备应用请求root权限
  14. Burp Suite Pro 教程
  15. angular和vue的差别
  16. cookie,session,fileter,liscen
  17. Python--Windows下安装虚拟环境
  18. 宕机不等于关机,阴魂不散的vm
  19. Windows 7 上面 redis 启动报错的处理
  20. 027.Zabbix的定期备份

热门文章

  1. python之解析csv
  2. OpenFeign使用笔记
  3. python学习---python基础一
  4. auto_ptr 浅析(转)
  5. eclipse中debug改变变量的值
  6. 使用navicat的SSH隧道连接数据库
  7. Python列表练习题
  8. 721. Accounts Merge合并电子邮件账户
  9. QuartJob的CronExpressionString规则详解
  10. loadrunner12-参数化以及参数化关联