在.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

.NetCore分布式部署中的DataProtection密钥安全性的更多相关文章

  1. .net Forms身份验证不能用在应用的分布式部署中吗?

    参照网上的一些方法,使用Forms身份验证对应用进行分布式部署,发现没有成功. 应用部署的两台内网服务器:192.168.1.19,192.168.1.87,使用Nginx做负载分配,配置完全相同:每 ...

  2. 分布式项目中 linux 服务器 部署jar 应用脚本 deploy.sh

    在实际项目的部署中,尤其是分布式项目,有很多服务的jar包需要 部署,这里抽取出公用的 deploy的脚本 下面是不含jdk配置的 #!/bin/bash JAVA_OPTIONS_INITIAL=- ...

  3. 技术分享 | 在GreatDB分布式部署模式中使用Chaos Mesh做混沌测试

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1. 需求背景与万里安全数据库软件GreatDB分布式部署模式介绍 1.1 需求背景 混沌测试是检测分布式系统不确定性.建 ...

  4. hadoop部署中遇到ssh设置的问题

    尽管hadoop和一些培训视频课程上讲分布式部署比较详细,但是在部署时仍遇到了一些小问题,在此mark一下: 1.linux的namenode主机上安装了ssh,也启动了ssh,并且执行了: /etc ...

  5. Web分布式部署,跨应用程序Forms身份验证的集成方案

    最近一个项目要求进行分布式部署.保证在双十一期间系统的正常运行,虽然该系统平时访问量不是很大,但是基于业务需要,必须在至少两台服务器上部署. 该系统需要登录后才可以使用,首先需要解决分布式部署的用户状 ...

  6. Hadoop学习------Hadoop安装方式之(三):分布式部署

    这里为了方便直接将单机部署过的虚拟机直接克隆,当然也可以不这样做,一个个手工部署. 创建完整克隆——>下一步——>安装位置.等待一段时间即可. 我这边用了三台虚拟机,分别起名master, ...

  7. Azkaban安装及分布式部署(multiple-executor)

    参考文章:https://blog.csdn.net/weixin_35852328/article/details/79327996 官网:https://azkaban.readthedocs.i ...

  8. hyperledger fabric 1.0.5 分布式部署 (六)

    如何在相同的peer 节点上创建多个 channel 作者在hyperledger fabric 1.0.5 分布式部署 (五)已经向读者们介绍了一个简单的fabric 的部署流程,那么根据上一篇博客 ...

  9. 完全分布式部署Hadoop

    完全分布式部署 Hadoop 分析: 1)准备 3 台客户机(关闭防火墙.静态 ip.主机名称) 2)安装 jdk 3)配置环境变量 4)安装 hadoop 5)配置环境变量 6)安装 ssh 7)配 ...

随机推荐

  1. Thymeleaf系列五 迭代,if,switch语法

      1. 概述 这里介绍thymeleaf的编程语法,本节主要包括如下内容 迭代语法:th:each; iteration status 条件语法:th:if; th:unless switch语法: ...

  2. 深入浅出 Java Concurrency (5): 原子操作 part 4 CAS操作

    在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...

  3. 读书笔记--Linux Shell脚本攻略

    总结的来说,这本书很实践性和实用性强,都是给的具体的例子,直接可以在终端操作实践,比单纯只看不动手务实多了,另外就是,这本书涵盖的内容也比较广,从文本操作到服务器管理到远程ssh等等,都给出来作者挑选 ...

  4. Ubuntu 安装VNC

    ubuntu:.安装x11vnc sudo apt-get install x11vnc .设置密码 x11vnc -storepasswd .启动x11vnc(每次windows远程控制,都需要启动 ...

  5. MyEclipse8.6启动后提示内存不足的解决方案(亲测,完美解决)

    转自:http://www.bubuko.com/infodetail-1625857.html 最近可能由于公司项目大了,启动MyEclipse后经常提示内存不足的警告框,如下: 其实点击close ...

  6. ehlib 用法记录

    点列头排序 1.add  ehlibado.pas  to project. 2.grideh>ColumnDefValues>Title>TitleButton=true; 3.g ...

  7. Redis 哨兵模式 带密码单机

    语法 https://segmentfault.com/a/1190000002680804 启动3台redis 6379,6380,6381 cp 多个redis.conf文件 开启daemoniz ...

  8. js 判断空数组,空对象!

    var attr1 = [ ]; var obj1 = { }; console.log(isEmpty(attr1)); console.log(isEmpty(obj1)); function i ...

  9. 发布spring jar包, 报错

    org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Una ...

  10. Centos7手动编译安装Python3

    Python3的安装方式非常的简单,首先去到Python下载目录下载想要的Python包,这里我选择了3.6.5版本 $ wget https://www.python.org/ftp/python/ ...