DNX 核心:Encrypt/Decrypt?
DNX Core: Encrypt/Decrypt?
我正在将网站移植到 dnx core/aspnet5/mvc6。我需要将密码存储到数据库中的第 3 方站点(它本质上是一个聚合器)。
在早期版本的 mvc 中,我使用 类 像 RijndaelManaged 那样做到了这一点。但这些似乎并不存在于 dnx 核心中。事实上,我没能在 dnx 核心中找到很多关于任何通用 encryption/decryption 内容的文档。
对于 mvc6 站点中的 encrypting/decrypting 单个字段值,推荐的方法是什么?我不想加密整个 sql 服务器数据库。
或者我应该寻找一种不同的方法来存储访问受密码保护的第 3 方站点所需的凭据吗?
查看 DataProtection API documentation
他们的 guidance on using it for persistent data protection 有点冒险,但他们说没有技术原因你不能这样做。基本上,要持久存储受保护的数据,您需要愿意允许使用过期的密钥对其进行取消保护,因为密钥在您保护它之后可能会过期。
对我来说使用它似乎是合理的,我在 my own project.
中使用它
由于 IPersistedDataProtector 只提供字节数组的方法,我做了几个扩展方法来将字节从字符串来回转换。
public static class DataProtectionExtensions
{
public static string PersistentUnprotect(
this IPersistedDataProtector dp,
string protectedData,
out bool requiresMigration,
out bool wasRevoked)
{
bool ignoreRevocation = true;
byte[] protectedBytes = Convert.FromBase64String(protectedData);
byte[] unprotectedBytes = dp.DangerousUnprotect(protectedBytes, ignoreRevocation, out requiresMigration, out wasRevoked);
return Encoding.UTF8.GetString(unprotectedBytes);
}
public static string PersistentProtect(
this IPersistedDataProtector dp,
string clearText)
{
byte[] clearBytes = Encoding.UTF8.GetBytes(clearText);
byte[] protectedBytes = dp.Protect(clearBytes);
string result = Convert.ToBase64String(protectedBytes);
return result;
}
}
我还创建了一个帮助程序 class 专门用于在我的 SiteSettings 对象持久保存到数据库之前保护它的某些属性。
using cloudscribe.Core.Models;
using Microsoft.AspNet.DataProtection;
using Microsoft.Extensions.Logging;
using System;
namespace cloudscribe.Core.Web.Components
{
public class SiteDataProtector
{
public SiteDataProtector(
IDataProtectionProvider dataProtectionProvider,
ILogger<SiteDataProtector> logger)
{
rawProtector = dataProtectionProvider.CreateProtector("cloudscribe.Core.Models.SiteSettings");
log = logger;
}
private ILogger log;
private IDataProtector rawProtector = null;
private IPersistedDataProtector dataProtector
{
get { return rawProtector as IPersistedDataProtector; }
}
public void Protect(ISiteSettings site)
{
if (site == null) { throw new ArgumentNullException("you must pass in an implementation of ISiteSettings"); }
if (site.IsDataProtected) { return; }
if (dataProtector == null) { return; }
if (site.FacebookAppSecret.Length > 0)
{
try
{
site.FacebookAppSecret = dataProtector.PersistentProtect(site.FacebookAppSecret);
}
catch (System.Security.Cryptography.CryptographicException ex)
{
log.LogError("data protection error", ex);
}
}
// ....
site.IsDataProtected = true;
}
public void UnProtect(ISiteSettings site)
{
bool requiresMigration = false;
bool wasRevoked = false;
if (site == null) { throw new ArgumentNullException("you must pass in an implementation of ISiteSettings"); }
if (!site.IsDataProtected) { return; }
if (site.FacebookAppSecret.Length > 0)
{
try
{
site.FacebookAppSecret = dataProtector.PersistentUnprotect(site.FacebookAppSecret, out requiresMigration, out wasRevoked);
}
catch (System.Security.Cryptography.CryptographicException ex)
{
log.LogError("data protection error", ex);
}
catch (FormatException ex)
{
log.LogError("data protection error", ex);
}
}
site.IsDataProtected = false;
if (requiresMigration || wasRevoked)
{
log.LogWarning("DataProtection key wasRevoked or requires migration, save site settings for " + site.SiteName + " to protect with a new key");
}
}
}
}
如果应用程序在数据被保护后需要迁移到其他机器那么你也想控制密钥位置,默认将密钥放在机器的 OS 密钥环上作为我对它的理解很像过去的 machinekey,您可以在 web.config 中覆盖它以方便携带。
当然,此时保护密钥是你的责任。我的项目启动时有这样的代码
//If you change the key persistence location, the system will no longer automatically encrypt keys
// at rest since it doesn’t know whether DPAPI is an appropriate encryption mechanism.
services.ConfigureDataProtection(configure =>
{
string pathToCryptoKeys = appBasePath + Path.DirectorySeparatorChar
+ "dp_keys" + Path.DirectorySeparatorChar;
// these keys are not encrypted at rest
// since we have specified a non default location
// that also makes the key portable so they will still work if we migrate to
// a new machine (will they work on different OS? I think so)
// this is a similar server migration issue as the old machinekey
// where we specified a machinekey in web.config so it would not change if we
// migrate to a new server
configure.PersistKeysToFileSystem(new DirectoryInfo(pathToCryptoKeys));
});
所以在这个例子中我的密钥存储在 appRoot/dp_keys 中。
如果您想手动操作;
添加对 System.Security.Cryptography.Algorithms
的引用
然后你可以通过create方法创建每个算法类型的实例。例如;
var aes = System.Security.Cryptography.Aes.Create();
我正在将网站移植到 dnx core/aspnet5/mvc6。我需要将密码存储到数据库中的第 3 方站点(它本质上是一个聚合器)。
在早期版本的 mvc 中,我使用 类 像 RijndaelManaged 那样做到了这一点。但这些似乎并不存在于 dnx 核心中。事实上,我没能在 dnx 核心中找到很多关于任何通用 encryption/decryption 内容的文档。
对于 mvc6 站点中的 encrypting/decrypting 单个字段值,推荐的方法是什么?我不想加密整个 sql 服务器数据库。
或者我应该寻找一种不同的方法来存储访问受密码保护的第 3 方站点所需的凭据吗?
查看 DataProtection API documentation
他们的 guidance on using it for persistent data protection 有点冒险,但他们说没有技术原因你不能这样做。基本上,要持久存储受保护的数据,您需要愿意允许使用过期的密钥对其进行取消保护,因为密钥在您保护它之后可能会过期。
对我来说使用它似乎是合理的,我在 my own project.
中使用它由于 IPersistedDataProtector 只提供字节数组的方法,我做了几个扩展方法来将字节从字符串来回转换。
public static class DataProtectionExtensions
{
public static string PersistentUnprotect(
this IPersistedDataProtector dp,
string protectedData,
out bool requiresMigration,
out bool wasRevoked)
{
bool ignoreRevocation = true;
byte[] protectedBytes = Convert.FromBase64String(protectedData);
byte[] unprotectedBytes = dp.DangerousUnprotect(protectedBytes, ignoreRevocation, out requiresMigration, out wasRevoked);
return Encoding.UTF8.GetString(unprotectedBytes);
}
public static string PersistentProtect(
this IPersistedDataProtector dp,
string clearText)
{
byte[] clearBytes = Encoding.UTF8.GetBytes(clearText);
byte[] protectedBytes = dp.Protect(clearBytes);
string result = Convert.ToBase64String(protectedBytes);
return result;
}
}
我还创建了一个帮助程序 class 专门用于在我的 SiteSettings 对象持久保存到数据库之前保护它的某些属性。
using cloudscribe.Core.Models;
using Microsoft.AspNet.DataProtection;
using Microsoft.Extensions.Logging;
using System;
namespace cloudscribe.Core.Web.Components
{
public class SiteDataProtector
{
public SiteDataProtector(
IDataProtectionProvider dataProtectionProvider,
ILogger<SiteDataProtector> logger)
{
rawProtector = dataProtectionProvider.CreateProtector("cloudscribe.Core.Models.SiteSettings");
log = logger;
}
private ILogger log;
private IDataProtector rawProtector = null;
private IPersistedDataProtector dataProtector
{
get { return rawProtector as IPersistedDataProtector; }
}
public void Protect(ISiteSettings site)
{
if (site == null) { throw new ArgumentNullException("you must pass in an implementation of ISiteSettings"); }
if (site.IsDataProtected) { return; }
if (dataProtector == null) { return; }
if (site.FacebookAppSecret.Length > 0)
{
try
{
site.FacebookAppSecret = dataProtector.PersistentProtect(site.FacebookAppSecret);
}
catch (System.Security.Cryptography.CryptographicException ex)
{
log.LogError("data protection error", ex);
}
}
// ....
site.IsDataProtected = true;
}
public void UnProtect(ISiteSettings site)
{
bool requiresMigration = false;
bool wasRevoked = false;
if (site == null) { throw new ArgumentNullException("you must pass in an implementation of ISiteSettings"); }
if (!site.IsDataProtected) { return; }
if (site.FacebookAppSecret.Length > 0)
{
try
{
site.FacebookAppSecret = dataProtector.PersistentUnprotect(site.FacebookAppSecret, out requiresMigration, out wasRevoked);
}
catch (System.Security.Cryptography.CryptographicException ex)
{
log.LogError("data protection error", ex);
}
catch (FormatException ex)
{
log.LogError("data protection error", ex);
}
}
site.IsDataProtected = false;
if (requiresMigration || wasRevoked)
{
log.LogWarning("DataProtection key wasRevoked or requires migration, save site settings for " + site.SiteName + " to protect with a new key");
}
}
}
}
如果应用程序在数据被保护后需要迁移到其他机器那么你也想控制密钥位置,默认将密钥放在机器的 OS 密钥环上作为我对它的理解很像过去的 machinekey,您可以在 web.config 中覆盖它以方便携带。 当然,此时保护密钥是你的责任。我的项目启动时有这样的代码
//If you change the key persistence location, the system will no longer automatically encrypt keys
// at rest since it doesn’t know whether DPAPI is an appropriate encryption mechanism.
services.ConfigureDataProtection(configure =>
{
string pathToCryptoKeys = appBasePath + Path.DirectorySeparatorChar
+ "dp_keys" + Path.DirectorySeparatorChar;
// these keys are not encrypted at rest
// since we have specified a non default location
// that also makes the key portable so they will still work if we migrate to
// a new machine (will they work on different OS? I think so)
// this is a similar server migration issue as the old machinekey
// where we specified a machinekey in web.config so it would not change if we
// migrate to a new server
configure.PersistKeysToFileSystem(new DirectoryInfo(pathToCryptoKeys));
});
所以在这个例子中我的密钥存储在 appRoot/dp_keys 中。
如果您想手动操作;
添加对 System.Security.Cryptography.Algorithms
的引用然后你可以通过create方法创建每个算法类型的实例。例如;
var aes = System.Security.Cryptography.Aes.Create();