第三方服务集成需要管理大量密钥:AppId/AppSecret、API Key、OAuth Token、RSA 私钥。密钥泄露是最严重的安全风险。
密钥在哪里
安全约定
密钥不进入日志
RequestLogHandler / SensitiveDataRedactor 自动脱敏敏感头和字段。脱敏策略覆盖:
| 位置 | 脱敏方式 |
|---|---|
| HTTP Header | 按名称匹配(Authorization、X-API-Key 等)→ *** |
| Query String | 按参数名匹配(access_token、secret 等)→ *** |
| Form Body | 按字段名匹配 → *** |
| JSON Body | 按路径匹配(递归遍历)→ *** |
| XML Body | 按元素名匹配 → *** |
密钥不进入异常详情
// ✓ 正确——ProviderMessage 不含密钥throw new PaymentException( domain: "Payment", provider: "Alipay", message: "签名验证失败", errorCode: "SIGN_FAILED");
// ❌ 错误——异常消息包含完整密钥throw new Exception($"签名失败,私钥: {options.AppPrivateKey}");密钥不进入健康检查
Health Check 只报告连接状态,不回显凭据:
// ✓ 只检查配置是否存在,不验证密钥有效性public Task<HealthCheckResult> CheckHealthAsync(...){ if (string.IsNullOrEmpty(_options.AppId)) return Task.FromResult(HealthCheckResult.Unhealthy("AppId 未配置")); return Task.FromResult(HealthCheckResult.Healthy());}字节数组密钥用后清除
签名器在 Dispose 时清除持有密钥的字节数组:
internal sealed class AlipaySigner : IDisposable{ private byte[]? _privateKeyBytes;
public void Dispose() { if (_privateKeyBytes is not null) { Array.Clear(_privateKeyBytes); // ① 清除内存中的密钥 _privateKeyBytes = null; } }}密钥来源选择
| 环境 | 推荐方式 | 示例 |
|---|---|---|
| 本地开发 | dotnet user-secrets | dotnet user-secrets set "Alipay:AppSecret" "..." |
| 测试/预发布 | 环境变量或 CI Secret | ALIPAY_APP_SECRET=... |
| 生产 | Vault / KMS / 云密钥服务 | 通过 IIntegrationCredentialResolver 注入 |