最小可见与字段级加密:EF Core 拦截器 + Always Encrypted

EF Core拦截器与Always Encrypted实战

最小可见与字段级加密:EF Core 拦截器 + Always Encrypted 🔐



0)TL;DR 🧾

  • Always Encrypted (AE) 将加/解密前移到客户端驱动(如 Microsoft.Data.SqlClient),数据库只持久化密文;启用 Secure Enclave 可获得原地(in-place)重加密与更丰富的机密查询能力。

  • EF Core DbCommandInterceptor 在发送前:

    1. 统一设置 SqlCommand.ColumnEncryptionSetting(默认 Enabled,部分只读场景可降到 ResultSetOnly);
    2. 强制参数化(命中敏感列的非参数化文本 SQL 直接阻断);
    3. 埋点审计(租户、用户、模式、列清单、TraceId)。
  • 密钥治理:CMK/CEK 由 SSMS/PowerShell 管理;CEK 支持在线轮换,Enclave 下可 in-place;同一列仅能绑定一个 CEK(要“按租户密钥”必须分库/分架构/分表或分片)。


1)问题与边界 🧭

  • 目标:敏感列加密存储、透明解密、全链路可审计。

  • 限制

    • 无 Enclave:确定性加密仅支持等值类操作(可索引);随机化更安全但基本不可查询。
    • Enclave:扩展机密查询并可 in-place 重加密,但仍受函数/运算限制与环境前提约束。
  • 与 DDM/RLS 的关系(互补):

    • AE:存储/传输阶段的机密性;
    • DDM(动态数据掩码):结果显示层遮蔽(“看得到但看不全”);
    • RLS(行级安全):按主体控制行可见性(“看不见就不返回”)。

2)关键概念速读 💡

  • CMK/CEK:列主密钥(CMK)包裹列加密密钥(CEK),CEK 对真实列加密。一个 CEK 可服务多列,但“一列只绑定一个 CEK”(同一时刻)。
  • 确定性 vs 随机化:确定性支持等值/索引(存在枚举风险);随机化保密性强但不支持筛选。
  • Secure Enclave:受信执行环境(SQL Server 2019+ / Azure SQL),支持 in-place 加/重/解密与更丰富的机密查询。
  • 驱动:务必使用 Microsoft.Data.SqlClient(新特性前进方向);System.Data.SqlClient 已停止功能性演进,应迁移。

3)目标架构(ABP/EF Core 集成)🏗️

加密参数/透明解密
列加密元数据
证明/会话
业务代码
EF Core
DbCommandInterceptor
策略注入/审计/强制参数化
SqlClient
Column Encryption Setting=Enabled
TDS 连接
SQL Server / Azure SQL
CEK 绑定在列
Secure Enclave
CMK: 证书/Key Vault/HSM

要点

  • 加/解密发生在客户端;数据库只存密文。
  • Enclave 可与驱动建立证明会话,启用更多机密查询与 in-place 重加密
  • 列级绑定:同一物理列 只能绑定一把 CEK。

4)环境准备与密钥配置(可复现)🛠️

4.1 SSMS 向导(最快)⚡

Always Encrypted 向导:选择列 → 选择/创建 CMK/CEK → 选择加密类型(确定性/随机化)→ 执行(可生成脚本留存)。

4.2 PowerShell(自动化/可回滚)

# 需要:Install-Module SqlServer -Scope CurrentUser
$server="localhost"; $instance="DEFAULT"; $db="ContosoHR"
$path="SQLSERVER:\SQL\$server\$instance\Databases\$db"

# 1) 创建 CMK(示例:Windows 证书存储)
New-SqlColumnMasterKey -Path $path -Name "CMK1" `
  -KeyStoreProviderName "MSSQL_CERTIFICATE_STORE" `
  -KeyPath "CurrentUser/My/<THUMBPRINT>"

# 2) 生成 CEK(由 CMK 包裹)
New-SqlColumnEncryptionKey -Path $path -Name "CEK1" -ColumnMasterKey "CMK1"

# 3) 加密列(示例:确定性)
$ssn = New-SqlColumnEncryptionSettings -ColumnName "dbo.Employees.SSN" `
  -EncryptionType Deterministic -ColumnEncryptionKey "CEK1"
Set-SqlColumnEncryption -Path $path -ColumnEncryptionSettings $ssn

# == 轮换 ==
# 新 CEK:CEK2
New-SqlColumnEncryptionKey -Path $path -Name "CEK2" -ColumnMasterKey "CMK1"
# 重加密(可批量;启用 Enclave 时可 in-place 降低时窗)
$ssn2 = New-SqlColumnEncryptionSettings -ColumnName "dbo.Employees.SSN" `
  -EncryptionType Deterministic -ColumnEncryptionKey "CEK2"
Set-SqlColumnEncryption -Path $path -ColumnEncryptionSettings $ssn2

5)EF Core 拦截器:策略化开关 + 强制参数化 + 审计 🧩

🎯 目标

  • 默认 Enabled纯读且无敏感参数的查询可降级为 ResultSetOnly
  • 命中敏感列且非参数化的文本 SQL 一律阻断
  • 放行驱动内部的参数加密元数据探测(sys.sp_describe_parameter_encryption)。
  • 执行后统一采集列清单ReaderExecuted/Async),避免遗漏。

5.1 注册(推荐:由 DI 注入到 DbContextOptions)

// Program.cs / Startup.cs
services.AddSingleton<AeCommandInterceptor>(); // 无状态或仅 Logger/AsyncLocal
services.AddDbContext<MyDbContext>((sp, opts) =>
{
   
   
    opts.AddInterceptors(sp.GetRequiredService<AeCommandInterceptor>());
    // ... 其他 EF 配置
});

5.2 拦截器实现(覆盖 Reader/NonQuery/Scalar 的同步/异步 + Executed 采集列清单)

using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore.Diagnostics;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Linq;

public class AeCommandInterceptor : DbCommandInterceptor
{
   
   
    private readonly IAePolicy _policy;
    private readonly ICommandAuditor _auditor;

    public AeCommandInterceptor(IAePolicy policy, ICommandAuditor auditor)
    {
   
    _policy = policy; _auditor = auditor; }

    // ---- 同步 Executing ----
    public override InterceptionResult<DbDataReader> ReaderExecuting(
        DbCommand command, CommandEventData eventData,
        InterceptionResult<DbDataReader> result)
    {
   
    Apply(command, eventData); return base.ReaderExecuting(command, eventData, result); }

    public override InterceptionResult<int
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kookoos

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值