.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)配 ...
随机推荐
- 精《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #7 Cgroup、Namespace、Linux容器
HACK #7 Cgroup.Namespace.Linux容器 本节将介绍Cgroup与Namespace以及通过这两个功能实现的容器功能.CgroupCgroup(control group)是将 ...
- Linux nohup和&的功效
nohup和&究竟有啥区别?不少同学进行了回复,但并不是所有同学都理解得全对,今天把自己挖的坑自己填了. 测试代码如下: 是一个输出hello与循环轮数的死循环程序,每输出一行就休眠1秒. 使 ...
- 深入浅出 Java Concurrency (5): 原子操作 part 4 CAS操作
在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...
- Python实践练习:选择性拷贝
题目 项目要求:编写一个程序,遍历一个目录树,查找特定扩展名的文件(诸如.pdf 或.jpg),不论这些文件的位置在哪里, 将它们拷贝到一个新的文件夹中. 代码 import os import sh ...
- ffmpeg默认输出中文为 UTF-8
在使用ffmpeg 进行对音视频文件解码输出信息的时候会出现乱码. 从网上找到了说ffmpeg默认格式 为 utf-8 如果vs工程使用的的 Unicode 则需要将 utf-8转 Unicode 才 ...
- spring mvc 映射器和适配器
映射器和适配器 1.非注解的映射器和适配器 a. 入门程序中的单个映射 BeanNameUrlHandlerMapping SimpleControllerHandlerAdapter b.另一种ma ...
- Eclipse开启或取消快速导航栏(toggle breadcrumb)
在Eclipse中快速调出导航栏 关闭导航栏: 在视图的设置中,去掉breadcrum的勾选状态
- 03-使用html静态页面展示执行效果
使用工作流框架可以做什么事情?写代码呗,没那么简单.
- Python3 sorted() 函数
Python3 sorted() 函数 Python3 内置函数 描述 sorted() 函数对所有可迭代的对象进行排序操作. sort 与 sorted 区别: sort 是应用在 list 上的 ...
- oracle 求班级平均分
select * from ( selectclass 班级,subject,avg(grade) avg_gradefrom student_score group by class,subject ...