我有一个连接到许多SQL Server的应用程序,用于监视和其他任务。目前,我只支持受信任的身份验证,因为我不必存储任何敏感内容。我想添加使用SQL身份验证(用户名/密码)的功能。
在会话之间存储此敏感数据的最佳方法是什么?我可以使用仅用户可用的证书或加密密钥吗?使用每个用户随机生成的注册表项来加密此信息是否足够安全?如果我有办法使用密钥(或创建并存储密钥),而计算机上没有其他用户可以访问它,那是理想的选择。
[我了解加密,所以我不要找教程-我正在寻找最安全的方法来保护我的应用程序的一个用户的配置数据不受其他用户的伤害。
使用Data Protection API (aka. DPAPI)。每次使用都有一个受其密码保护的密钥。您将密码/连接字符串存储在.config文件中,.Net框架提供了使用计算机密钥,用户密钥或RSA密钥对配置部分进行加密/解密的方法。不要按照自己的自定义方案重新发明轮子。使用注册表项绝对不是一个好主意。安全性来自机密,而不是访问保护:安全性必须依靠用户提供机密(登录时的密码),而不是无法访问的注册表项。
How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI
如Remus所说,使用DPAPI。但是,不要使用PInvoke方法(如您的链接示例中那样),而要使用ProtectedData类。那是围绕DPAPI的托管包装。许多示例使用PInvoke访问DPAPI,因为在.Net 2.0之前没有托管的方式来执行此操作。 DataProtectionScope类使您可以为当前用户或计算机加密/解密数据。
正如Remus指出的那样,存在用户/机器级别的加密。
我通常对这些事情感到恐惧,因为数据很容易相对丢失。
如果我是你,我会推出我自己的系统。使用在您的应用程序中硬编码的密钥对连接字符串进行加密,转换为Base64,然后将生成的加密的连接字符串存储在注册表中。
以下函数获取一个字符串,使用AES-256和指定的密钥对其进行加密,然后以base64作为结果,因此将其作为可打印字符串返回:
样本用法:
String connectionString = EncryptString(
"Provider=SQLOLEDB;Data Source=Lithium;User Id=sa;Password=hello",
"A fairly complicated password, like a guid: 8B4B0D73-84C9-4A1E-8DD2-9A189F84FD9B");
public static string EncryptString(string source, string key)
{
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(key, salt);
byte[] derivedKey = deriveBytes.GetBytes(derivedKeySize);
Rijndael rijndael = Rijndael.Create();
rijndael.Mode = cipherMode;
rijndael.Padding = paddingMode;
rijndael.KeySize = keySize;
rijndael.BlockSize = blockSize;
rijndael.FeedbackSize = blockSize; // no bigger than the blocksize
rijndael.Key = derivedKey;
rijndael.IV = iv;
ICryptoTransform transform = rijndael.CreateEncryptor();
byte[] encoded = Encoding.UTF8.GetBytes(source);
byte[] target = transform.TransformFinalBlock(encoded, 0, encoded.Length);
return Convert.ToBase64String(target);
}
public static string DecryptString(string source, string key)
{
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(key, salt);
byte[] derivedKey = deriveBytes.GetBytes(derivedKeySize);
Rijndael rijndael = Rijndael.Create();
rijndael.Mode = cipherMode;
rijndael.Padding = paddingMode;
rijndael.KeySize = keySize;
rijndael.BlockSize = blockSize;
rijndael.FeedbackSize = blockSize; // no bigger than the blocksize
rijndael.Key = derivedKey;
rijndael.IV = iv;
ICryptoTransform transform = rijndael.CreateDecryptor();
byte[] decoded = Convert.FromBase64String(source);
byte[] target = transform.TransformFinalBlock(decoded, 0, decoded.Length);
return Encoding.UTF8.GetString(target);
}
private static readonly byte[] iv = {
0x30,0xA6,0x65,0xDE,0x8C,0x63,0x17,0x44,
0xB6,0xFD,0xEA,0x5F,0x76,0xA1,0x1C,0x5F
};
private static readonly byte[] salt = {
0xF9,0x39,0x0C,0xE0,0x22,0xE0,0x8E,0x84,
0xB2,0x05,0x1E,0xA8,0x6D,0x1C,0x39,0xAC
};
private const int keySize = 256;
private const int blockSize = 128;
private const CipherMode cipherMode = CipherMode.CBC;
private const PaddingMode paddingMode = PaddingMode.PKCS7;
private const int derivedKeySize = 32;
任何形式的加密都仅与用于保护加密密钥的方法一样强大,并且大多数系统仍在努力将受保护的数据与其密钥或其他解密方法真正分开。例如,访问密码数据库的攻击者可以首先发起离线字典攻击以获得用户密码,然后以这些用户身份登录并“合法”请求在线服务提供商执行解密。更糟的是,获得加密密钥的内部人员或持久攻击者可以下载整个数据库并脱机执行解密。
为了防御此类攻击,外部加密服务可以将加密数据与解密功能完全分开。这确保了数据加密不能被反向工程,并且任何解密都必须在加密服务的配合下进行授权-甚至是离线的。
看一下该框架,该框架将帮助您进行每用户加密:https://virgilsecurity.com/purekit-mariadb-plugin/
该框架提供以下功能:
经过密码强化的加密。您将不会存储用户密码或其哈希值。 PureKit可保护用户或内部密码免遭数据泄露以及在线和离线攻击。
按用户加密。 PureKit可以按用户对任何大小的文件进行强大而快速的数据加密。
基于角色的加密。 PureKit为您提供创建和管理组(角色)以及使用范围(权限)的功能,以允许和拒绝其访问对诸如文件和数据之类的资源进行加密的加密密钥的访问。
安全数据和文件共享。 PureKit允许您和您的用户使用Virgil密钥管理服务安全地共享数据。
加密独立于数据库安全性进行。 PureKit提供端到端加密,因此,数据安全性不依赖任何设备,网络或云提供商。
折衷后的安全性。
通过要求同时访问数据库和远程加密服务器来解锁受保护的记录,PureKit允许您保护敏感数据(如PII,PHI和密码)免受未经授权的访问,即使数据库或其他在线存储设施受到威胁。用户密码和秘密密钥的零知识。
PureKit提供了一种数据和密码加密的方式,可以防止未经授权的各方了解密码或加密密钥的任何信息。此外,Virgil Security无法访问您的数据。被盗数据库的立即失效。
如果数据库被盗,PureKit允许旋转密钥和远程记录。