当前位置: 首页 > 科技观察

Asp.NETCore中如何优雅的管理用户机密数据

时间:2023-03-12 10:01:13 科技观察

本文转载自微信公众号《DotNET技术圈》,作者邹希源。转载本文请联系DotNET技术圈公众号。背景回顾在软件开发过程中,通常的做法是使用配置文件来管理应用程序运行时需要用到的某些参数。在早期的VB/VB.NET中,.ini文件通常用于配置管理;在.NETFX开发中,我们倾向于使用web.config文件,这些文件通过配置appsetting的配置部分来处理;而在.NETCore开发中,我们有一个新的基于json格式的appsetting.json文件。无论采用哪种方式,其实配置管理一直都是一项看似简单,但影响深远的基础工作。特别是配置的安全性贯穿于整个应用程序。如果安全问题没有做好,极有可能给系统带来不可控的风向。源代码比配置文件安全吗?有些人认为将配置存储在源代码中可能看起来比将配置文件存储在明文中更安全,但实际上是“皇帝的新衣”。前不久,笔者的一个朋友给我讲了一个故事:他说同事离职后,直接将自己写的一段代码上传到了github的公共仓库,这段代码中包含了一些幸运的机密数据原公司的行为被GitHub安全机制提前发现,及时终止该行为,否则后果不堪设想。因此,笔者查阅了因有意或无意泄露企业秘密而造成企业损失的案例,发现数量不少。例如,大疆前员工通过Github泄露公司源代码被罚款20万元并判处半年监禁的案例[1],也是典型案例。该员工离职后,将包含关键配置信息的源代码上传至github公共仓库,被黑客利用,导致大量用户隐私数据被黑客获取,该前员工最终被拘留。前大疆员工通过Github泄露公司源代码,被罚款20万元,被判半年监禁图片来源:http://www.digitalmunition.com/WhyIWalkedFrom3k.pdf[2]大多数IT公司都会进行就业前的背景调查,一旦你有犯罪记录,你可能会错过很多IT公司;即使你成为了一名企业家,你也可能面临无法与许多正规公司合作的问题。小结因此,安全问题不容小觑。不管时间多忙,都不要轻易在源代码或配置文件中记录数据库连接字符串或其他包含敏感信息的内容。此时,一旦出现问题,往往是非常严重的问题。如何实现在.NETFX时代,我们可以通过对web.config文件的关键配置段进行加密的方式来保护我们的敏感信息。在.NETCore中,自然有这些东西,接下来我会简单介绍一下。开发环境和生产环境的不同配置加密方式,希望能给读者带来启示。开发环境在开发环境中,我们可以使用visualstudio工具提供的usersecretmanager,仅用0行代码就可以轻松完成关键配置段的处理。SecretManager概述根据微软官方文档[3]:ASP.NETCoreSecretManager[4]工具提供了另一种在开发过程中将机密保存在源代码之外的方法。要使用SecretManager工具,请在您的项目文件中安装包Microsoft.Extensions.Configuration.SecretManager。如果依赖项存在并已恢复,您可以使用dotnetuser-secrets命令从命令行设置机密的值。这些秘密将存储在用户配置文件目录中的JSON文件中(详细信息因操作系统而异),与源代码无关。SecretManager工具设置的Secret由使用该Secret的项目的UserSecretsId属性组织。因此,您必须确保在项目文件中设置了UserSecretsId属性,如以下代码片段所示。默认值是由VisualStudio分配的GUID,但实际的字符串并不重要,只要它在整个计算机中是唯一的即可。UniqueIdentifyingStringSecretManager工具允许开发人员在ASP.NETCore应用程序开发期间存储和检索敏感数据。敏感数据存储在与应用程序源代码不同的位置。由于SecretManager将机密与源代码分开存储,因此敏感数据不会提交到源代码存储库。但是,机密管理器不会加密存储的敏感数据,因此不应将其视为受信任的存储。敏感数据作为键值对存储在JSON文件中。最好不要在开发和测试环境中使用生产机密。参见引文[5]。存储位置在windows平台下,机密数据的存储位置为:%APPDATA%\Microsoft\UserSecrets\\secrets.json,在Linux/MacOs平台下,机密数据的存储位置为:~/.microsoft/usersecrets//secrets.json在前面的文件路径中,`user_secrets_id`将用.csproj文件中指定的值替换UserSecretsId。Windows环境下使用secretmanager在Windows下,如果使用VisualStudio2019作为主要开发环境,只需在项目上右击,选择菜单【ManageUserSecrets】即可添加用户机密数据。在用户机密数据的管理上,增加的配置信息与传统的配置信息没有区别。{"ConnectionStrings":{"Default":"Server=xxx;Database=xxx;UserID=xxx;Password=xxx;"}}我们还可以使用IConfiguration和IOptions来访问配置。在非Windows/非VisualStudio环境下使用secretmanager安装dotnet-cli后,在控制台输入dotnetuser-secretsinit之前的命令,在UserSecretsId.csproj文件的PropertyGroup中添加一个.csproj元素。UserSecretsId是项目独有的Guid值。netcoreapp3.179a3edd0-2092-40a2-a04d-dcb46d5ca9edsetsecretsdotnetuser-secretsset"Movies:ServiceApiKey""12345"列出机密dotnetuser-secretslistdeletesecretsdotnetuser-secretsremove"Movies:ConnectionString"clearallsecretsdotnetuser-secretsclear生产环境secretsmanager为开发者提供了一种在开发环境中保存机密数据的方法,但是不建议在开发环境中使用,我应该怎么办如果我想在生产环境中保存机密数据怎么办?根据微软的官方文档,推荐使用AzureKeyVault[6]来保护机密数据,但是。.我不是贵云的用户(当然,我买不起贵云,因为贵云太贵了,但我个人问题[手动狗头]图片picture)。其次,类似AzureKeyValut的套件,比如其他的云,几乎都有,所以我们都可以用。但。.如果你和我一样不想通过第三方依赖来解决这个问题,那还不如用最简单的方法,比如AES加密。使用AES加密配置部分该方法与通常使用AES加密和解密字符串的方法相同,这里不再赘述。在平时的开发过程中使用DataProtectionApi(DataProtectApiimplementation),能够手工进行AES加密是一个非常好的习惯,而微软官方提供的DataProtectionAPI进一步简化了这个过程,只需要调整Api完成相应的数据加密操作。关于数据保护API,Savorboard[7]写了3篇博客讨论这个技术问题。您可以参考以下文章以获取信息。(接下来贴出代码,不感兴趣的请出门左转,代码不能完全运行,查看代码来源[11])首先,注入配置项publicstaticIServiceCollectionAddProtectedConfiguration(thisIServiceCollectionservices,stringdirectory){services.AddDataProtection().PersistKeysToFileSystem(newDirectoryInfo(目录)).UseCustomCryptographicAlgorithms(newManagedAuthenticatedEncryptorConfiguration{EncryptionAlgorithmType=typeof(Aes),EncryptionAlgorithmKeySize=256,ValidationAlgorithmType=typeof(HMACSHA256)});;returnservices加密/解密配置部分。(使用AES算法的数据保护机制)publicclassProtectedConfigurationSection:IConfigurationSection{privatereadonlyIDataProtectionProvider_dataProtectionProvider;privatereadonlyIConfigurationSection_section;privatereadonlyLazy_protector;publicProtectedConfigurationSection(IDataProtectionProviderdataProtectionProvider,IConfigurationSectionsection){_dataProtectionProvider=dataProtectionProvider;_section=section;_protector=newLazy(()=>dataProtectionProvider.CreateProtector(部分。路径));,x));}publicIChangeTokenGetReloadToken(){return_section.GetReloadToken();}publicstringthis[stringkey]{get=>GetProtectedValue(_section[key]);设置=>_section[key]=_protector.Value.Protect(value);}publicstringKey=>_section.Key;publicstringPath=>_section.Path;publicstringValue{get=>GetProtectedValue(_section.Value);set=>_section.Value=_protector.Value.Protect(value);}privatestringGetProtectedValue(stringvalue){if(value==null)returnnull;return_protector.Value.Unprotect(value);}}同样,使用前,将要加密的字符串转成BASE64明文,然后使用数据保护API对数据进行处理得到处理后的字符串privatereadonlyIDataProtectionProvider_dataProtectorTokenProvider;publicTokenAuthController(IDataProtectionProviderdataProtectorTokenProvider){}[Route("encrypt"),HttpGet,HttpPost]publicstringEncrypt(stringorvalue){varsection,protect_dataProtectorTokenProvider.CreateProtector(section);returnprotector.Protect(value);}然后替换配置中对应的内容文件。{"ConnectionStrings":{"Default":"Hereistheencryptedstring"}}然后我们就可以按照通常的方式获取IOptions了。问题公众号【DotNET骚操作】账号主人[周杰]提出了以下几点:1.在生产环境中,使用AES加密其实还是不够安全的行为。充其量,它可以骗过产品经理。毕竟,几句简单的语句就可以倾倒机密数据。或许在这种情况下,我们应该优先考虑accessKeyId/accessSecret,通过设置多级子账号的API授权机制来管理机密数据,而不是直接暴露数据库连接字符串等关键配置信息。此外,应定期更改数据库的密码,以尽量减少类似问题可能带来的风险。数据保护API也提供了类似的机制,使开发者可以轻松管理机密数据的时效性。2、配置文件放在CI/CD中,发布时组装在CI/CD中,然后运维只负责管理CI/CD的账户信息,绝密数据由其他的。好吧,我完全同意他的第二种方法。另外,考虑到运维也可能有意无意泄露机密数据,如果运维配备了《刑法》,让他每天补习【侵犯商业秘密罪】相关条款,这个过程更加闭环。结束语本文简单介绍了如何在开发环境中使用用户机密管理器,在生产环境中使用AES+IDataProvider来保护我们在.NETCore中的敏感用户数据。由于时间仓促,如有不周之处,敬请批评指正。参考资料[1]大疆前员工通过Github泄露公司源代码,被罚款20万元,判刑半年:https://www.infoq.cn/article/RZzfel1m6-h8pSK8TTC9[2]http://www.digitalmunition.com/WhyIWalkedFrom3k.pdf:http://www.digitalmunition.com/WhyIWalkedFrom3k.pdf[3]微软官方文档:https://docs.microsoft.com/zh-cn/dotnet/architecture/microservices/secure-net-microservices-web-applications/developer-app-secrets-storage[4]SecretManager:https://docs.microsoft.com/zh-cn/aspnet/core/security/app-secrets#secret-manager[5]查看引文:https://nvisium.com/blog/2019/05/02/Dev-Secrets-and-the-ASP-NET-Core-Secret-Manager.html[6]AzureKeyVault:https://docs。microsoft.com/zh-cn/dotnet/architecture/microservices/secure-net-microservices-web-applications/azure-key-vault-protects-secrets[7]Savorboard:https://home.cnblogs.com/u/savorboard/[8]ASP.NETCore数据保护(数据保护集群场景)【上篇】:https://www.cnblogs.com/savorboard/p/dotnetcore-data-protection.html[9]ASP.NETCore数据保护(数据保护集群场景)【中】:https://www.cnblogs.com/savorboard/p/dotnet-core-data-protection.html[10]ASP.NETCore数据保护(数据保护集群场景)【第二部分】:https://www.cnblogs.com/savorboard/p/dotnetcore-data-protected-farm.html[11]查看代码:https://stackoverflow.com/questions/36062670/encrypted-configuration-in-asp-net-core本文首发于西园个人博客:https://www.techq.xyz/2020/06/09/%E6%8A%80%E6%9C%AF/how-to-manage-user-secret-in-develop-and-production/