背景
回顾
在软件开发过程中,使用配置文件来管理某些对应用程序运行中需要使用的参数是常见的作法。在早期VB/VB.NET时代,经常使用.ini文件来进行配置管理;而在.NET FX开发中,我们则倾向于使用web.config文件,通过配置appsetting的配置节来处理;而在.NET Core开发中,我们有了新的基于json格式的appsetting.json文件。
无论采用哪种方式,其实配置管理从来都是一件看起来简单,但影响非常深远的基础性工作。尤其是配置的安全性,贯穿应用程序的始终,如果没能做好安全性问题,极有可能会给系统带来不可控的风向。
源代码比配置文件安全么?
有人以为把配置存放在源代码中,可能比存放在明文的配置文件中似乎更安全,其实是“皇帝的新装”。
在前不久,笔者的一位朋友就跟我说了一段故事:他说一位同事在离职后,直接将曾经写过的一段代码上传到github的公共仓库,而这段代码中包含了某些涉及到原企业的机密数据,还好被github的安全机制提前发现而及时终止了该行为,否则后果不堪设想。
于是,笔者顺手查了一下由于有意或无意泄露企业机密,造成企业损失的案例,发现还真不少。例如大疆前员工通过 Github 泄露公司源代码,被罚 20 万、获刑半年 这起案件,也是一个典型的案例。
该员工离职后,将包含关键配置信息的源代码上传到github的公共仓库,被黑客利用,使得大量用户私人数据被黑客获取,该前员工最终被刑拘。
大部分IT公司都会在入职前进行背景调查,而一旦有案底,可能就已经与许多IT公司无缘;即便是成为创业者,也可能面临无法跟很多正规企业合作的问题。
小结
所以,安全性问题不容小觑,哪怕时间再忙,也不要急匆匆的就将数据库连接字符串或其他包含敏感信息的内容轻易的记录在源代码或配置文件中。在这个点上,一旦出现问题,往往都是非常严重的问题。
如何实现
机密管理器概述
根据微软官方文档 的描述:
机密管理器工具在开发 ASP.NET Core 项目的过程中存储敏感数据。 在此上下文中,一段敏感数据是应用程序机密。 应用密钥存储在与项目树不同的位置。 应用程序机密与特定项目关联或在多个项目之间共享。
在VS2019项目中,选中项目,右键,点击:管理用户机密(G)菜单,打开用户机密存储文件 secrets.json
secrets.json 文件和普通的Json文件没有区别,他不会主动对存储的数据进行加密,他的存储位置和项目位置不一致,因此这个文件不会随项目文件通过 Git Svn 等代码管理工具上传至服务器。
在windows平台下,机密数据的存放位置为(我项目中的机密文件存储位置):
选择项目,编辑项目文件,我们会发现项目文件中<UserSecretsId>节对应的值是 secrets.json 文件存储的文件夹名称。它是一个GUID,值可以是任意的,但对应项目是唯一的。
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <UserSecretsId>fb727eb4-fd16-4383-8187-a299822a3faf</UserSecretsId> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.5" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.5" /> </ItemGroup> </Project>
设置机密
可以通过 .NET Core CLI 工具执行命令来设置机密,列出机密,删除机密,添加机密,如果没有安装 NET Core CLI 工具 ,则可以直接编辑 secrets.json 文件来设置机密,查看机密等操作。
使用.NET Core CLI 工具命令如下(参考自微软教程:https://docs.microsoft.com/zh-cn/aspnet/core/security/app-secrets?view=aspnetcore-3.1&tabs=windows)
设置机密
dotnet user-secrets set "Movies:ServiceApiKey" "12345"
列出机密
dotnet user-secrets list
删除机密
dotnet user-secrets remove "Movies:ConnectionString"
清除所有机密
dotnet user-secrets clear
在我的VS2019上,个人没能找到NET Core CLI 工具(如果大家有谁能找到或者有教程安装,请回复指点),因此,上述命令对我没有,我采用简单粗暴的方法直接编辑 secrets.json 文件
例如,增加一个配置项:Movies:ServiceApiKey,并设置值为:123456
{ "Movies": { "ServiceApiKey": "123456", "ConnectionString": "Server=(localdb)\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true" } }
机密管理器为开发者在开发环境下提供了一种保留机密数据的方法,但在开发环境下是不建议使用的。开发环境几乎无秘密可言....哈哈
上述介绍了机密数据的保存,设置等操作,那么怎么使用这些机密数据呢?
如何访问机密
1、直接读取的方式,和配置文件读取方法一致(请参考我的博客 , 配置文件的读取:NetCore 配置文件---直接读取及选项模式读取)
var _moviesApiKey = ConfigRoot["Movies:ServiceApiKey"];
2、将机密映射到 POCO
将整个对象文本映射到 POCO (带有属性的简单 .NET 类)对于聚合相关属性十分有用。
假设应用的机密 json文件包含以下两个机密:
{ "Movies": { "ServiceApiKey": "12345", "ConnectionString": "Server=(localdb)\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true" } }
若要将上述机密映射到 POCO,请使用Configuration
API 的对象关系图绑定功能。
其实也是我的上篇博客中所说的选项模式,他们几乎是一致的。
类:
public class MovieSettings { public string ConnectionString { get; set; } public string ServiceApiKey { get; set; } }
读取方法,请参考博客 :NetCore 配置文件---直接读取及选项模式读取)
var moviesConfig = ConfigRoot.GetSection("Movies") .Get<MovieSettings>(); var moviesApiKey = moviesConfig.ServiceApiKey;
用机密替换字符串
虽然说机密文件相对安全,但是我们还是有必要针对机密文件存储的值进行加密,例如Md5、RSA、AES等加密模式。这样文件是安全的,存储的内容也是安全加密的。
参考至:在Asp.NET Core中如何优雅的管理用户机密数据
及
参考至:ASP.NET Core 中的开发中安全存储应用机密
@天才卧龙的博客