尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

前端与后端安全密钥传输方案及.NET Core实现

前端与后端安全密钥传输方案及.NET Core实现 1. 密钥传输的安全挑战与核心方案选型在分布式系统开发中前端JavaScript应用与后端.NET Core WebAPI服务之间的密钥传输是个典型的安全痛点。去年我们团队在金融项目中就遇到过这样的场景移动端需要从服务端动态获取AES加密密钥来处理敏感数据但直接明文传输密钥无异于在互联网上裸奔。1.1 常见风险场景分析先看几个真实案例中的安全隐患中间人攻击2019年某电商平台API密钥被截获攻击者通过WiFi嗅探获取了前端与后端通信的加密密钥参数泄露密钥通过URL参数或FormData明文传输被浏览器历史记录或服务器日志意外留存算法漏洞使用ECB模式等不安全加密方式导致密钥可被推导1.2 解决方案的技术选型经过多次压力测试我们最终确定的方案组合是graph TD A[前端请求密钥] -- B[非对称加密传输] B -- C[后端生成临时密钥对] C -- D[前端用公钥加密密钥] D -- E[后端用私钥解密] E -- F[建立安全通道]具体技术栈选择非对称加密RSA 2048bit前端加密/后端解密对称加密AES-256-CBC后续业务数据传输密钥派生PBKDF2 HMAC-SHA256传输保护TLS 1.3 证书固定关键提示绝对不要在代码中硬编码密钥我们曾发现某合作伙伴将生产环境密钥直接写在JavaScript文件里导致重大安全事故。2. .NET Core WebAPI端的实现细节2.1 安全密钥生成服务首先在后端创建密钥生成接口// KeyGeneratorService.cs public class KeyGeneratorService { public (string publicKey, string privateKey) GenerateRSAKeys() { using var rsa new RSACryptoServiceProvider(2048); return ( rsa.ToXmlString(false), // 公钥 rsa.ToXmlString(true) // 私钥 ); } public string GenerateAESKey() { using var aes Aes.Create(); aes.KeySize 256; aes.GenerateKey(); return Convert.ToBase64String(aes.Key); } }2.2 安全传输API端点创建WebAPI控制器处理密钥请求[ApiController] [Route(api/[controller])] public class KeyExchangeController : ControllerBase { private readonly KeyGeneratorService _keyService; public KeyExchangeController(KeyGeneratorService keyService) { _keyService keyService; } [HttpGet(init)] public IActionResult GetPublicKey() { var (publicKey, _) _keyService.GenerateRSAKeys(); return Ok(new { publicKey }); } [HttpPost(exchange)] public IActionResult ExchangeKey([FromBody] EncryptedKeyModel model) { using var rsa new RSACryptoServiceProvider(); rsa.FromXmlString(_privateKey); // 从安全存储加载私钥 byte[] encryptedBytes Convert.FromBase64String(model.EncryptedKey); byte[] decryptedBytes rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.Pkcs1); string aesKey Encoding.UTF8.GetString(decryptedBytes); // 存储密钥与客户端会话关联 _sessionStorage.StoreKey(model.ClientId, aesKey); return Ok(new { success true }); } }2.3 关键安全措施密钥生命周期管理每个客户端会话使用独立密钥设置合理的密钥过期时间建议不超过24小时实现密钥轮换机制防御中间人攻击services.AddHttpsRedirection(options { options.HttpsPort 443; options.RedirectStatusCode StatusCodes.Status308PermanentRedirect; }); services.AddHsts(options { options.Preload true; options.IncludeSubDomains true; options.MaxAge TimeSpan.FromDays(365); });日志脱敏处理[AttributeUsage(AttributeTargets.Parameter)] public class SensitiveDataAttribute : Attribute, IResultFilter { public void OnResultExecuting(ResultExecutingContext context) { if (context.Result is ObjectResult objResult) { if (objResult.Value.ToString().Contains(Key)) { context.HttpContext.Response.Headers.Add(X-Sensitive-Data, redacted); } } } }3. JavaScript客户端的实现方案3.1 使用Web Cryptography API现代浏览器提供的加密API比传统的JS库更安全// 初始化加密环境 async function initCrypto() { // 从后端获取RSA公钥 const response await fetch(/api/keyexchange/init); const { publicKey } await response.json(); // 生成AES密钥 const aesKey await window.crypto.subtle.generateKey( { name: AES-CBC, length: 256 }, true, [encrypt, decrypt] ); // 导出密钥材料 const exportedKey await window.crypto.subtle.exportKey(raw, aesKey); // 使用RSA公钥加密 const encryptedKey await window.crypto.subtle.encrypt( { name: RSA-OAEP }, publicKey, exportedKey ); // 发送到后端 await fetch(/api/keyexchange/exchange, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ clientId: generateClientId(), encryptedKey: arrayBufferToBase64(encryptedKey) }) }); return aesKey; }3.2 关键安全实践存储安全// 安全存储密钥的方案比较 const storageStrategies { sessionStorage: () { // 会话结束时自动清除 sessionStorage.setItem(aesKey, key); }, indexedDB: () { // 更安全的存储方式 const db await openDB(SecureStore, 1); await db.put(keys, key, current); }, memoryOnly: () { // 最高安全级别 let _key null; return { set: (key) { _key key; }, get: () _key }; } };防御XSS攻击// CSP策略示例 meta http-equivContent-Security-Policy contentdefault-src self; script-src self unsafe-inline unsafe-eval; connect-src https://api.yourdomain.com; style-src self unsafe-inline请求保护// 所有请求自动添加防护头 fetch(/api/keyexchange, { headers: { X-Requested-With: XMLHttpRequest, X-Content-Type-Options: nosniff, X-Frame-Options: DENY } });4. 完整通信流程与异常处理4.1 安全握手时序初始化阶段Client-Server: GET /api/keyexchange/init Server--Client: RSA Public Key Client-Client: Generate AES Key Client-Client: Encrypt AES Key with RSA Public Key Client-Server: POST /api/keyexchange {encryptedKey} Server--Client: 200 OK业务通信阶段async function sendEncryptedData(data) { const iv window.crypto.getRandomValues(new Uint8Array(16)); const encrypted await window.crypto.subtle.encrypt( { name: AES-CBC, iv: iv }, aesKey, new TextEncoder().encode(JSON.stringify(data)) ); return { iv: arrayBufferToBase64(iv), payload: arrayBufferToBase64(encrypted) }; }4.2 常见问题排查指南错误现象可能原因解决方案InvalidKeyException密钥长度不匹配检查AES密钥是否为256位(32字节)Padding is invalid填充模式不一致确保前后端都使用PKCS7400 Bad Request密钥格式错误验证Base64编码是否正确加密结果不一致IV向量不同每次加密使用随机IV并传输4.3 性能优化技巧密钥缓存策略// 带过期的内存缓存 const keyCache { _keys: new Map(), get(keyName) { const entry this._keys.get(keyName); if (entry entry.expiry Date.now()) { return entry.value; } return null; }, set(keyName, value, ttl 300000) { this._keys.set(keyName, { value, expiry: Date.now() ttl }); } };批量加密优化// .NET端的批量解密 public Liststring BulkDecrypt(ListEncryptedData dataList) { using var aes Aes.Create(); aes.Key _currentKey; var results new ConcurrentBagstring(); Parallel.ForEach(dataList, data { aes.IV Convert.FromBase64String(data.Iv); using var decryptor aes.CreateDecryptor(); byte[] buffer Convert.FromBase64String(data.Payload); using var ms new MemoryStream(buffer); using var cs new CryptoStream(ms, decryptor, CryptoStreamMode.Read); using var reader new StreamReader(cs); results.Add(reader.ReadToEnd()); }); return results.ToList(); }5. 进阶安全增强措施5.1 密钥分片技术为提升安全性可以实现密钥分片存储// 在客户端拆分密钥 function splitKey(key) { const part1 key.substring(0, 16); const part2 key.substring(16); return { part1: await encryptWithPublicKey(part1), part2: await encryptWithPublicKey(part2) }; } // 服务端重组 public string RebuildKey(KeyParts parts) { var part1 _rsa.Decrypt(parts.Part1); var part2 _rsa.Decrypt(parts.Part2); return part1 part2; }5.2 动态密钥派生基于主密钥派生会话密钥public string DeriveSessionKey(string masterKey, string sessionId) { using var hmac new HMACSHA256(Encoding.UTF8.GetBytes(masterKey)); byte[] hash hmac.ComputeHash(Encoding.UTF8.GetBytes(sessionId)); return Convert.ToBase64String(hash.Take(32).ToArray()); }5.3 硬件安全模块集成对于金融级应用建议集成HSM// 使用Azure Key Vault的示例 public async Taskstring GetKeyFromVault(string keyName) { var client new SecretClient( new Uri(https://your-vault.vault.azure.net/), new DefaultAzureCredential()); KeyVaultSecret secret await client.GetSecretAsync(keyName); return secret.Value; }在实际项目中我们通过这套方案成功通过了PCI DSS三级认证。核心经验是密钥安全不是单一技术点而是需要从生成、传输、存储、使用到销毁的全生命周期管理。每次密钥交换都应该有独立的加密通道并且要定期审计密钥使用情况。
返回列表