安全是现代软件开发的基石。.NET 提供了完整的安全编程基础设施,包括加密算法、哈希函数、数字签名以及安全编码实践。本文将从实际应用角度出发,讲解 .NET 中加密与安全的核心概念和最佳实践。
哈希与校验 密码哈希 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 using System.Security.Cryptography;byte [] hash = SHA256.HashData(Encoding.UTF8.GetBytes("password123" ));Console.WriteLine(Convert.ToHexString(hash)); string HashPassword (string password ){ var salt = RandomNumberGenerator.GetBytes(16 ); var hash = Rfc2898DeriveBytes.Pbkdf2( password, salt, iterations: 100 _000, HashAlgorithmName.SHA256, outputLength: 32 ); return Convert.ToBase64String(salt) + ":" + Convert.ToBase64String(hash); } bool VerifyPassword (string password, string storedHash ){ var parts = storedHash.Split(':' ); var salt = Convert.FromBase64String(parts[0 ]); var hash = Convert.FromBase64String(parts[1 ]); var computedHash = Rfc2898DeriveBytes.Pbkdf2( password, salt, 100 _000, HashAlgorithmName.SHA256, hash.Length); return CryptographicOperations.FixedTimeEquals(hash, computedHash); }
使用 CryptographicOperations.FixedTimeEquals 进行哈希比较,防止计时攻击(Timing Attack)。
常见哈希算法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 string ComputeFileHash (string filePath ){ using var stream = File.OpenRead(filePath); var hash = SHA256.HashData(stream); return Convert.ToHexString(hash).ToLowerInvariant(); } var hash = SHA256.HashData(utf8Bytes);string ComputeHmac (string message, byte [] key ){ var hmac = HMACSHA256.HashData(key, Encoding.UTF8.GetBytes(message)); return Convert.ToHexString(hmac); }
对称加密 加密和解密使用相同密钥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class AesEncryption { public static (byte [] ciphertext, byte [] iv, byte [] key ) Encrypt (string plaintext ) { using var aes = Aes.Create(); aes.GenerateKey(); aes.GenerateIV(); byte [] ciphertext = aes.EncryptCbc( Encoding.UTF8.GetBytes(plaintext), aes.IV, PaddingMode.PKCS7); return (ciphertext, aes.IV, aes.Key); } public static string Decrypt (byte [] ciphertext, byte [] key, byte [] iv ) { using var aes = Aes.Create(); byte [] plaintext = aes.DecryptCbc( ciphertext, iv, PaddingMode.PKCS7); return Encoding.UTF8.GetString(plaintext); } } public static byte [] EncryptAuthenticated (string plaintext, byte [] key, byte [] nonce ){ using var aes = new AesGcm(key); byte [] ciphertext = new byte [plaintext.Length]; byte [] tag = new byte [AesGcm.TagByteSizes.MaxSize]; aes.Encrypt(nonce, Encoding.UTF8.GetBytes(plaintext), ciphertext, tag); return [.. ciphertext, .. tag]; }
非对称加密 公钥加密,私钥解密。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class RsaEncryption { public static (string publicKey, string privateKey ) GenerateKeys () { using var rsa = RSA.Create(2048 ); string publicKey = rsa.ToXmlString(false ); string privateKey = rsa.ToXmlString(true ); return (publicKey, privateKey); } public static string Encrypt (string plaintext, string publicKeyXml ) { using var rsa = RSA.Create(); rsa.FromXmlString(publicKeyXml); byte [] encrypted = rsa.Encrypt( Encoding.UTF8.GetBytes(plaintext), RSAEncryptionPadding.OaepSHA256); return Convert.ToBase64String(encrypted); } public static string Decrypt (string ciphertext, string privateKeyXml ) { using var rsa = RSA.Create(); rsa.FromXmlString(privateKeyXml); byte [] decrypted = rsa.Decrypt( Convert.FromBase64String(ciphertext), RSAEncryptionPadding.OaepSHA256); return Encoding.UTF8.GetString(decrypted); } }
ECDH —— 密钥交换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 using var alice = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP256);using var bob = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP256);byte [] alicePublicKey = alice.PublicKey.ExportSubjectPublicKeyInfo();byte [] bobPublicKey = bob.PublicKey.ExportSubjectPublicKeyInfo();byte [] aliceShared = alice.DeriveKeyMaterial( ECDiffieHellmanPublicKey.CreateFromSubjectPublicKeyInfo( bobPublicKey, out _)); byte [] bobShared = bob.DeriveKeyMaterial( ECDiffieHellmanPublicKey.CreateFromSubjectPublicKeyInfo( alicePublicKey, out _));
数字签名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class DigitalSignature { public static byte [] SignData (string data, string privateKeyXml ) { using var rsa = RSA.Create(); rsa.FromXmlString(privateKeyXml); return rsa.SignData( Encoding.UTF8.GetBytes(data), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } public static bool VerifySignature ( string data, byte [] signature, string publicKeyXml ) { using var rsa = RSA.Create(); rsa.FromXmlString(publicKeyXml); return rsa.VerifyData( Encoding.UTF8.GetBytes(data), signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } }
SecureString 与安全内存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using System.Security;using var securePwd = new SecureString();foreach (char c in "P@ssw0rd" ) securePwd.AppendChar(c); securePwd.MakeReadOnly(); byte [] sensitiveData = Encoding.UTF8.GetBytes("my-api-key" );try { } finally { CryptographicOperations.ZeroMemory(sensitiveData); }
安全编码实践 1. SQL 注入防护 1 2 3 4 5 6 7 string sql = $"SELECT * FROM Users WHERE Name = '{userInput} '" ; using var cmd = new SqlCommand( "SELECT * FROM Users WHERE Name = @name" ); cmd.Parameters.AddWithValue("@name" , userInput);
2. XSS 防护 1 2 3 4 5 6 7 8 string userContent = "<script>alert('xss')</script>" ;string safe = System.Web.HttpUtility.HtmlEncode(userContent);string urlSafe = System.Web.HttpUtility.UrlEncode(userContent);
3. CSRF 防护 1 2 3 4 5 6 [ValidateAntiForgeryToken ] public IActionResult ChangePassword (ChangePasswordModel model ){ }
4. 证书验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var handler = new HttpClientHandler{ ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }; var safeHandler = new HttpClientHandler();var customHandler = new HttpClientHandler{ ServerCertificateCustomValidationCallback = (sender, cert, chain, errors) => { if (errors == SslPolicyErrors.None) return true ; return false ; } };
加密算法选型
算法
用途
推荐状态
SHA-256/384/512
文件校验、HMAC
✅ 推荐
PBKDF2 / bcrypt / Argon2
密码存储
✅ 推荐
AES-256-GCM
数据加密
✅ 强力推荐
RSA 2048+ / ECDSA
非对称加密/签名
✅ 推荐
HMAC-SHA256
消息完整性校验
✅ 推荐
MD5 / SHA-1
任何安全用途
❌ 已废弃
DES / 3DES
任何加密用途
❌ 已废弃
RC4
任何用途
❌ 已废弃
总结 :安全编程不是简单地”添加加密”——而是在正确的地方使用正确的算法,并正确处理密钥、输入验证、输出编码等全链路安全问题。.NET 提供了丰富的加密 API,但开发者仍需了解何时使用对称 vs 非对称、何时使用认证加密、以及如何在性能和安全之间取得平衡。记住:永远不要自己实现加密算法,永远使用经过广泛审查的标准库。