.NetCore分布式部署中的DataProtection密钥安全性
在.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密钥安全性的更多相关文章
- .net Forms身份验证不能用在应用的分布式部署中吗?
参照网上的一些方法,使用Forms身份验证对应用进行分布式部署,发现没有成功. 应用部署的两台内网服务器:192.168.1.19,192.168.1.87,使用Nginx做负载分配,配置完全相同:每 ...
- 分布式项目中 linux 服务器 部署jar 应用脚本 deploy.sh
在实际项目的部署中,尤其是分布式项目,有很多服务的jar包需要 部署,这里抽取出公用的 deploy的脚本 下面是不含jdk配置的 #!/bin/bash JAVA_OPTIONS_INITIAL=- ...
- 技术分享 | 在GreatDB分布式部署模式中使用Chaos Mesh做混沌测试
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1. 需求背景与万里安全数据库软件GreatDB分布式部署模式介绍 1.1 需求背景 混沌测试是检测分布式系统不确定性.建 ...
- hadoop部署中遇到ssh设置的问题
尽管hadoop和一些培训视频课程上讲分布式部署比较详细,但是在部署时仍遇到了一些小问题,在此mark一下: 1.linux的namenode主机上安装了ssh,也启动了ssh,并且执行了: /etc ...
- Web分布式部署,跨应用程序Forms身份验证的集成方案
最近一个项目要求进行分布式部署.保证在双十一期间系统的正常运行,虽然该系统平时访问量不是很大,但是基于业务需要,必须在至少两台服务器上部署. 该系统需要登录后才可以使用,首先需要解决分布式部署的用户状 ...
- Hadoop学习------Hadoop安装方式之(三):分布式部署
这里为了方便直接将单机部署过的虚拟机直接克隆,当然也可以不这样做,一个个手工部署. 创建完整克隆——>下一步——>安装位置.等待一段时间即可. 我这边用了三台虚拟机,分别起名master, ...
- Azkaban安装及分布式部署(multiple-executor)
参考文章:https://blog.csdn.net/weixin_35852328/article/details/79327996 官网:https://azkaban.readthedocs.i ...
- hyperledger fabric 1.0.5 分布式部署 (六)
如何在相同的peer 节点上创建多个 channel 作者在hyperledger fabric 1.0.5 分布式部署 (五)已经向读者们介绍了一个简单的fabric 的部署流程,那么根据上一篇博客 ...
- 完全分布式部署Hadoop
完全分布式部署 Hadoop 分析: 1)准备 3 台客户机(关闭防火墙.静态 ip.主机名称) 2)安装 jdk 3)配置环境变量 4)安装 hadoop 5)配置环境变量 6)安装 ssh 7)配 ...
随机推荐
- 安装配置Android开发环境SDK
引言: 好搞事情,搞点移动端测试高大尚的东西,首先先得把环境搭建起来: 1.下载 握了个草,很多网站都直接推荐到android官网去下载,叔不知google官网早就被我大天朝给墙了,对于不喜欢FQ的天 ...
- django 短链接改成长连接
from django.conf import settings from django.core.wsgi import get_wsgi_application from gunicorn.app ...
- 搜索框请输入关键字 onfocus 和 onblur
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 迷你MVVM框架 avalonjs 1.3.4发布
发现一个以前从来没发现的大BUG,紧急发布此版本. fix getEachProxy BUG,此BUG会导致监控数组在删除某元素然后再添加元素时出现问题. avalon ms-on-*绑定添加一个钩子 ...
- Graphics.Blit
[Graphics.Blit] 需求注意第4个参数,用4个参数pass用于指定使用哪一个pass.默认值为-1,即使用所有的pass. 参考:file:///C:/Program%20Files%20 ...
- 26.Remove Duplicates from Sorted Array(Array)
Given a sorted array, remove the duplicates in place such that each element appear only once and ret ...
- 使用IntelliJ IDEA,gradle开发Java web应用步骤
最近 正在学习gradle构建工具的使用,看了一堆的文档,有点一知半解,索性动作实践一把,在以后的自己的项目中尝试使用看看.目前手头用的是IntelliJ IDEA 14,搭建了一天终于明白怎么集成g ...
- yii 关于如何改变默认访问的控制器(site)
以前Yii1学了个皮毛就没去管了,现在想重新捡起来Yii2.0.2却出来了,于是搭建好环境来学习. 安装好Yii2后第一个想到的问题就是修改默认的控制器了. 按照网上所说,终于在/vendor/yii ...
- gp sql
appendonly -- drop table if exists test_appendonly; -- create table test_appendonly with(appendonly= ...
- Java 设计模式系列(七)桥接模式
Java 设计模式系列(七)桥接模式 桥接模式(Bridge)是一种结构型设计模式.Bridge 模式基于类的最小设计原则,通过使用封装.聚合及继承等行为让不同的类承担不同的职责.它的主要特点是把抽象 ...