目录
-
密码安全的核心概念
-
加密 vs 哈希:何时使用?
-
密钥管理的重要性
-
常见攻击手段(中间人攻击、彩虹表)
-
-
基础加密技术
-
对称加密(AES)
-
非对称加密(RSA)
-
哈希算法(SHA3、HMAC)
-
-
现代安全实践
-
密码存储方案(PBKDF2、BCrypt)
-
数据保护API(Microsoft DPAPI)
-
安全随机数生成(CSPRNG)
-
-
代码实战
-
AES加密解密完整流程
-
RSA密钥对生成与加密
-
使用BCrypt安全存储密码
-
-
安全陷阱与防御
-
不要使用ECB模式!
-
密钥硬编码的风险
-
防止Padding Oracle攻击
-
-
企业级解决方案
-
Azure Key Vault集成
-
硬件安全模块(HSM)
-
-
常见问题解答
1. 密码安全的核心概念
加密 vs 哈希
特性 | 加密 | 哈希 |
---|---|---|
可逆性 | 是 | 否 |
适用场景 | 数据传输(如信用卡号) | 密码存储 |
典型算法 | AES、RSA | SHA3、PBKDF2、BCrypt |
密钥管理三原则
-
保密性:主密钥必须安全存储(如HSM)
-
轮换策略:定期更换加密密钥
-
最小权限:按需分配密钥访问权限
2. 基础加密技术
AES对称加密(CBC模式示例)
using System.Security.Cryptography;public class AesHelper
{public static (string cipherText, string iv) Encrypt(string plainText, byte[] key){using Aes aes = Aes.Create();aes.Key = key;aes.Mode = CipherMode.CBC; // 必须使用CBC或GCM模式aes.Padding = PaddingMode.PKCS7;// 生成随机IV(16字节)aes.GenerateIV();byte[] iv = aes.IV;ICryptoTransform encryptor = aes.CreateEncryptor();byte[] encrypted;using (var ms = new MemoryStream()){using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)){byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);cs.Write(plainBytes, 0, plainBytes.Length);}encrypted = ms.ToArray();}return (Convert.ToBase64String(encrypted), Convert.ToBase64String(iv));}public static string Decrypt(string cipherText, byte[] key, string ivBase64){using Aes aes = Aes.Create();aes.Key = key;aes.IV = Convert.FromBase64String(ivBase64);aes.Mode = CipherMode.CBC;aes.Padding = PaddingMode.PKCS7;ICryptoTransform decryptor = aes.CreateDecryptor();byte[] cipherBytes = Convert.FromBase64String(cipherText);using (var ms = new MemoryStream(cipherBytes))using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))using (var sr = new StreamReader(cs)){return sr.ReadToEnd();}}
}
RSA非对称加密
using System.Security.Cryptography;public class RsaHelper
{// 生成2048位密钥对public static (string publicKey, string privateKey) GenerateKeyPair(){using RSA rsa = RSA.Create(2048);return (Convert.ToBase64String(rsa.ExportRSAPublicKey()),Convert.ToBase64String(rsa.ExportRSAPrivateKey()));}public static string Encrypt(string plainText, string publicKeyBase64){byte[] publicKey = Convert.FromBase64String(publicKeyBase64);using RSA rsa = RSA.Create();rsa.ImportRSAPublicKey(publicKey, out _);byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes(plainText), RSAEncryptionPadding.OaepSHA256);return Convert.ToBase64String(encrypted);}public static string Decrypt(string cipherText, string privateKeyBase64){byte[] privateKey = Convert.FromBase64String(privateKeyBase64);using RSA rsa = RSA.Create();rsa.ImportRSAPrivateKey(privateKey, out _);byte[] decrypted = rsa.Decrypt(Convert.FromBase64String(cipherText), RSAEncryptionPadding.OaepSHA256);return Encoding.UTF8.GetString(decrypted);}
}
3. 现代安全实践
密码存储方案(PBKDF2 + Salt)
using System.Security.Cryptography;public class PasswordHasher
{// 生成密码哈希(推荐参数)public static (string hash, string salt) HashPassword(string password){byte[] salt = new byte[32];using var rng = RandomNumberGenerator.Create();rng.GetBytes(salt);int iterations = 150000; // OWASP 2021推荐值using var pbkdf2 = new Rfc2898DeriveBytes(password,salt,iterations,HashAlgorithmName.SHA512);byte[] hash = pbkdf2.GetBytes(64); // 64字节=512位return (Convert.ToBase64String(hash),Convert.ToBase64String(salt));}// 验证密码public static bool VerifyPassword(string password, string storedHash, string storedSalt){byte[] salt = Convert.FromBase64String(storedSalt);byte[] hash = Convert.FromBase64String(storedHash);using var pbkdf2 = new Rfc2898DeriveBytes(password,salt,150000,HashAlgorithmName.SHA512);byte[] testHash = pbkdf2.GetBytes(64);return CryptographicOperations.FixedTimeEquals(hash, testHash);}
}
Microsoft数据保护API(DPAPI)
// 适合本地数据保护(自动管理密钥)
using Microsoft.AspNetCore.DataProtection;public class DataProtector
{private readonly IDataProtector _protector;public DataProtector(IDataProtectionProvider provider){_protector = provider.CreateProtector("AppName.Purpose");}public string Protect(string input) => _protector.Protect(input);public string Unprotect(string protectedData) => _protector.Unprotect(protectedData);
}
4. 安全陷阱与防御
AES加密的致命错误
// 错误示例:使用ECB模式(不安全的!)
aes.Mode = CipherMode.ECB; // ❌ 相同输入产生相同输出,易被分析// 正确做法:使用CBC或GCM模式
aes.Mode = CipherMode.CBC; // ✅ 需要随机IV
aes.GenerateIV(); // 每次加密生成新IV
密钥存储的典型错误
// 错误:硬编码密钥
byte[] key = Encoding.ASCII.GetBytes("ThisIsASecretKey123"); // ❌// 正确:从安全存储获取
byte[] key = Convert.FromBase64String(ConfigurationManager.AppSettings["EncryptionKey"] // ✅ 使用密钥库
);
5. 企业级解决方案
Azure Key Vault集成
using Azure.Security.KeyVault.Keys.Cryptography;public async Task<string> EncryptWithAzureKeyVault(string text)
{var credential = new DefaultAzureCredential();var cryptoClient = new CryptographyClient(new Uri("https://your-vault.vault.azure.net/keys/key-name/"),credential);byte[] data = Encoding.UTF8.GetBytes(text);EncryptResult result = await cryptoClient.EncryptAsync(EncryptionAlgorithm.RsaOaep, data);return Convert.ToBase64String(result.Ciphertext);
}
6. 常见问题解答
Q1:应该选择对称还是非对称加密?
-
对称加密(AES):速度快,适合大数据量(如文件加密)
-
非对称加密(RSA):适合密钥交换或小数据加密
Q2:如何安全存储加密密钥?
-
开发环境:使用
dotnet user-secrets
-
生产环境:Azure Key Vault/AWS KMS/HSM
Q3:加密后的数据如何比较?
-
使用固定时间比较函数防止时序攻击:
// 正确方式 CryptographicOperations.FixedTimeEquals(hash1, hash2);// 错误方式 if (hash1 == hash2) { ... } // ❌ 可能泄露比较时间
Q4:如何迁移旧加密系统?
-
解密旧数据(使用旧密钥)
-
用新算法/密钥重新加密
-
销毁旧密钥(物理安全)