目录
密码安全的核心概念
加密 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:如何迁移旧加密系统?
解密旧数据(使用旧密钥)
用新算法/密钥重新加密
销毁旧密钥(物理安全)