在.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. sql多表更新使用别名(小技巧)

    update     A set     A.CityRegionID=B.ParentID,     A.CityName=(select RegionName from Common_Region ...

  2. 像素(PX)转其它长度单位(mm、cm...)

    今天想把px转成mm为单位,因像素跟其它单位比值的大小会跟屏幕设置的分辨率大小而不定,因此不能以固定的数值去计算. 解决方法是 页面上放一个高度为1mm的隐藏块 <div id="di ...

  3. centos7使用tinyproxy搭建简单http(s)服务器,无用户密码验证

    1  安装 yum install tinyproxy 2 查找配置文件地址 whereis tinyproxy.conf 3 编辑配置文件 vim tinyproxy.conf 把 allow 12 ...

  4. 48. Rotate Image (Array)

    You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise). ...

  5. UNITY WWW使用代码

    string detailURL = "https://www.xxx.xxx."; using (var w = new WWW(detailURL)) { yield retu ...

  6. for 续8

    ---------siwuxie095                 一个问题分析: 在 CMD 窗口输入: dir dir /b dir /b /ah dir C:\Windows dir C:\ ...

  7. zabbix 2.0 安装

    2.0环境 采用Centos6.3_64位操作系统 Zabbix安装 Zabbix 2.0 for RHEL5: # rpm -ivh http://repo.zabbix.com/zabbix/2. ...

  8. How to Restart Qt Application

    How to restart QtApplication As we know, Restarting Application means to exit current application, t ...

  9. springMVC入门程序。使用springmvc实现商品列表的展示。

    1.1 开发环境 本教程使用环境: Jdk:jdk1.7.0_72 Eclipse:mars Tomcat:apache-tomcat-7.0.53 Springmvc:4.1.3 1.2 需求 使用 ...

  10. [Training Video - 3] [Java Introduction] [Object Oriented Programming]

    Static and non-Static :  非静态方法(不带static)可以访问静态变量和方法(带static),但是反过来就不行. 类的静态成员(变量和方法)属于类本身,在类加载的时候就会分 ...