如何在ASP.NET MVC 5中用ErikEJ EF结合Azure KeyVault实现SQL Server Always Encrypted
分步实现ASP.NET MVC 5 + EF6 + SQL Server Always Encrypted + Azure KeyVault
一、确认EF6提供程序配置(已安装ErikEJ.EntityFramework.SqlServer)
- 修改
web.config中的EF提供程序,替换默认SQL Server提供程序:<entityFramework> <providers> <provider invariantName="Microsoft.Data.SqlClient" type="ErikEJ.EntityFramework.SqlServer.SqlProviderServices, ErikEJ.EntityFramework.SqlServer" /> </providers> </entityFramework> - 更新数据库连接字符串,使用
Microsoft.Data.SqlClient并启用列加密:<connectionStrings> <add name="YourDbContext" connectionString="Server=your-server;Database=your-db;User ID=your-user;Password=your-pass;Column Encryption Setting=Enabled;" providerName="Microsoft.Data.SqlClient" /> </connectionStrings>
二、搭建Azure KeyVault并配置权限
- 创建KeyVault:
- 登录Azure门户,新建KeyVault实例,选择合适区域、定价层,启用软删除和清除保护(强制安全要求)。
- 生成列主密钥(CMK):
- 进入KeyVault的「密钥」菜单,点击「生成/导入」,选择密钥类型为RSA,密钥大小≥2048,设置有效期后保存。
- 配置应用访问权限:
- 注册Azure AD服务主体:在Azure AD的「应用注册」中新建应用,记录客户端ID和客户端密钥(创建密钥时生成)。
- 回到KeyVault的「访问策略」,点击「添加访问策略」:
- 密钥权限选择「Get、Unwrap Key、Wrap Key」(满足Always Encrypted的密钥操作需求);
- 选择主体为刚注册的Azure AD应用;
- 保存策略。
三、Web应用集成Azure KeyVault(核心步骤)
方式1:使用服务主体(本地开发/非Azure部署)
- 安装NuGet包:
Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider - 在
web.config的appSettings中添加Azure AD凭据:<appSettings> <add key="AzureADTenantId" value="你的Azure AD租户ID" /> <add key="AzureADClientId" value="你的服务主体客户端ID" /> <add key="AzureADClientSecret" value="你的服务主体客户端密钥" /> </appSettings> - 在
Global.asax.cs的Application_Start中注册KeyVault密钥提供程序:using Microsoft.Data.SqlClient; using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; using Microsoft.IdentityModel.Clients.ActiveDirectory; protected void Application_Start() { // 初始化KeyVault令牌提供程序 var tenantId = ConfigurationManager.AppSettings["AzureADTenantId"]; var clientId = ConfigurationManager.AppSettings["AzureADClientId"]; var clientSecret = ConfigurationManager.AppSettings["AzureADClientSecret"]; var tokenProvider = new AzureKeyVaultTokenProvider( authority: $"https://login.microsoftonline.com/{tenantId}", clientId: clientId, clientSecret: clientSecret); // 注册KeyVault作为Always Encrypted的密钥存储 var azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider(tokenProvider); SqlConnection.RegisterColumnEncryptionKeyStoreProviders( new Dictionary<string, SqlColumnEncryptionKeyStoreProvider> { { SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider } }); // 原有MVC初始化代码 AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); }
方式2:使用Azure托管身份(部署到Azure App Service时推荐)
这种方式无需存储客户端密钥,更安全:
- 在Azure App Service的「身份」菜单中启用「系统分配」身份。
- 在KeyVault的「访问策略」中添加该App Service的身份,授予相同的密钥权限(Get、Unwrap Key、Wrap Key)。
- 修改
Global.asax.cs中的令牌提供程序:var tokenProvider = new ManagedIdentityTokenProvider(); // 后续注册代码与方式1一致
四、数据库与代码适配
- 创建列加密密钥(CEK):
- 使用SSMS连接数据库时,勾选「选项」中的「启用列加密」;
- 执行SQL创建CEK(关联KeyVault中的CMK):
CREATE COLUMN MASTER KEY MyCMK WITH ( KEY_STORE_PROVIDER_NAME = 'AZURE_KEY_VAULT', KEY_PATH = 'https://your-keyvault-name.vault.azure.net/keys/your-cmk-name/your-key-version' ); CREATE COLUMN ENCRYPTION KEY MyCEK WITH VALUES ( COLUMN_MASTER_KEY = MyCMK, ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x... -- 此值由SSMS自动生成,或通过向导创建 ); - 或者直接在表设计中,选择需要加密的列,设置「加密类型」为「确定性」或「随机化」,关联CEK后保存。
- 代码注意事项:
- 加密列的LINQ查询避免使用SQL端函数(如
LIKE、CONVERT),需在客户端处理逻辑; - 确保查询参数为强类型,EF会自动处理加密解密;
- 避免使用原始SQL查询,若必须使用,需确保参数通过EF上下文传递(自动加密)。
- 加密列的LINQ查询避免使用SQL端函数(如
五、测试验证
- 运行应用,执行读写加密列的操作,确认功能正常;
- 在SSMS中查看加密列数据,应显示为二进制加密值,无法直接读取;
- 查看KeyVault的「日志」,确认应用正在调用密钥操作(验证权限配置正确)。
内容的提问来源于stack exchange,提问作者Libin TK
相关产品推荐
相关产品推荐

