.net - 如何在 Winforms 应用程序中从 app.config 加载连接字符串后保护内存中的连接字符串
问题描述
我有一个旧应用程序,它使用 SQL Server 身份验证连接字符串连接到本地或基于 Intranet 的 SQL Server 实例。它目前使用 System.Configuration.ConfigurationManager 从 app.config 文件中获取连接字符串。但是,一旦从 app.config 文件中读取该连接字符串,它的值就会被加载到内存中,并且可以使用 Process Hacker 等工具公开以查看应用程序内存。我目前有一个带有方法的模块,该方法返回存储在 SecureString 对象中的连接字符串的值。连接字符串值在创建 ConnectionStringSection 对象时加载到内存中。app.config 连接字符串 xml 通过 microsoft 文档中给出的说明进行加密
我了解使用集成安全性是最佳实践,在这种情况下,我们的连接必须使用 SQL Server 身份验证。有没有办法消除或最小化应用程序内存中连接字符串的暴露?
Public Function GetConnectionString() As SecureString
Dim fileMap As ExeConfigurationFileMap = New ExeConfigurationFileMap
fileMap.ExeConfigFilename = Environment.CurrentDirectory + "\app.config"
Dim config As Configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None)
Dim section As ConnectionStringsSection = TryCast(config.GetSection("connectionStrings"), ConnectionStringsSection)
Dim secureString As New SecureString
For Each character As Char In section.ConnectionStrings("ConString").ConnectionString.ToCharArray
secureString.AppendChar(character)
Next
Return secureString
End Function
解决方案
这是我用来以纯文本形式保存密码的工作流程。
1)使用对称加密对连接字符串本身的密码进行加密,因此当它通过调用加载到内存中时
Dim section As ConnectionStringsSection = TryCast(config.GetSection("connectionStrings"), ConnectionStringsSection)
公开的值是加密值而不是纯文本。
https://docs.microsoft.com/en-us/dotnet/standard/security/encrypting-data
2) 解密密码并将其一次添加一个字符到 SecureString 对象进行存储。
https://docs.microsoft.com/en-us/dotnet/api/system.security.securestring?view=netframework-4.8
Public Shared Function DecryptString(ByVal srcString As String) As SecureString
Dim p As Byte() = Convert.FromBase64String(srcString)
Dim rv As RijndaelManaged = New RijndaelManaged
Dim ms As MemoryStream = New MemoryStream(p)
Dim cs As CryptoStream = New CryptoStream(ms, rv.CreateDecryptor(keyb, ivb), CryptoStreamMode.Read)
Dim secureString As New SecureString
Try
Do
Dim character As Integer = cs.ReadByte()
If character = -1 Then
Exit Do
End If
secureString.AppendChar(Chr(character))
Loop
Finally
ms.Close()
ms.Dispose()
cs.Close()
cs.Dispose()
End Try
secureString.MakeReadOnly()
Return secureString
End Function
3) 使用 SecureString 对象和用户名构造一个 SqlCredential 对象,其中“GetUserName()”从连接字符串中获取用户名,“GetPassword()”获取 SecureString 密码
Dim SqlCredential = New SqlCredential(GetUserName(), GetPassword())
4) 从这里您可以使用仅包含“Initial Catalog=;Data Source=;”的连接字符串构造一个 SQLConnection 对象 连接字符串和 SQLCredential 对象的一部分。“GetConnectionString()”将返回上述连接字符串。
Dim connection = New SqlConnection(GetConnectionString(), SqlCredential)
5) 如果您使用的是实体框架并且需要将该连接传递给您的 DBContext 对象,您可以使用此构造函数。
https://docs.microsoft.com/en-us/ef/ef6/fundamentals/connection-management
Dim myDbContext = New DBContext(New SqlConnection(ConnectionString, SqlCredential))
推荐阅读
- python - 如何找出熊猫中最大值出现的次数?
- sql - Impala 中的 REGEXP_EXTRACT
- r - Miss colorout 库(安装 rCharts)
- c++ - 是否可以获得根据 ADL 调用的函数的 decltype?
- assembly - 在程序集中设置显存VGA/VESA的自定义基地址
- python - 使用 PyMC3 时出现“TypeError: can't pickle CVM objects”
- javascript - 如何在不刷新页面的情况下设置全局变量原始值
- java - 使用 TreeTranslator 重命名不适用于 Kotlin 的函数
- android - 如何解析json数据并在网格视图中显示
- sql - 需要在 SQL 中找出从今天开始的 1 年和 1 年前的日期