为连接提供最低级别的安全性 strings/passwords
Provide minimum level of security to connection strings/passwords
一些信息:
-使用SQLite加密数据库的小型应用程序
-使用 Dotfuscator Community Edition 我仍然可以查看代码内部(即使方法名称已混淆)
sQliteConnection.SetPassword("Password=ThisIsMySuperSecretPassword");
-我不需要对代码本身(逻辑)进行高度保护,但我需要保护数据库密码
如果我使用像
这样的连接
PartA = "ThisIs"
PartB= "MySuper"
PartC= "SecretPassword"
Password = PartA + PartB + PartC
代码上4行不在一起,也许我可以有最低限度的保护
现在我可以更进一步了:
PartA = "Tehtibs5Iasu"
PartB= "M4ytS6uhpae3r5"
PartC= "S5efc2rhe8taP3ags5sgw4ogr5d6"
所以我有一个有效字符和一个无效字符只是为了混淆最终的潜伏者。我将使用 For 循环 "decrypt" 每个部分
这样的解决方案有多安全?
代码中还有其他保护密码的技巧吗?
Is there other tricks to protect a password inside the code?
是
(如果 'tricks' 你的意思是提供密码和使用连接字符串的替代方法)。
请注意,您不能在某人的 PC 上保密。但是特别是对于 SQLite 数据库,您可以通过不存储连接字符串来使获取连接字符串变得相当困难。演示数据库将使用密码:“”。也就是说,它将使用二进制密码。
具有所有共享方法的Class用于管理连接:
Imports System.Data.SQLite
Imports System.IO
Imports System.Drawing.Imaging
Friend Class SQLiteConn
' ToDo: obscure the name to hide the purpose ?
Friend Shared PasswordImg As Image
' full path to the dbfile
Friend Shared DBFile As String
' cant create one
Private Sub New()
End Sub
' this is to avoid exposing any method which returns the PW Byte()
Friend Shared Sub SetPassword(dbcon As SQLiteConnection)
If PasswordImg Is Nothing Then
Throw New ArgumentNullException("PasswordImg")
End If
dbcon.SetPassword(ImageToByteArray(PasswordImg))
End Sub
Friend Shared Sub ChangePassword(newPW As Image)
' not tested, I think this is correct
Using dbCon As New SQLiteConnection(GetLiteConnStr())
dbCon.SetPassword(ImageToByteArray(newPW))
' to do: add error handling,
' only set pwImg on success
PasswordImg = newPW
End Using
End Sub
' the connection string is not persisted
' to make it harder to copy the byte[] ... it only
' exists momentarliy
Friend Shared Function GetLiteConnStr() As String
Dim cb As New SQLiteConnectionStringBuilder
If String.IsNullOrEmpty(DBFile) Then
Throw New ArgumentNullException("DbFile")
End If
cb.DataSource = DBFile
cb.HexPassword = ImageToByteArray(PasswordImg)
cb.Pooling = True
' add other needed options
Return cb.ConnectionString
End Function
Private Shared Function ImageToByteArray(img As Image) As Byte()
Dim tmpData As Byte()
Using ms As New MemoryStream()
img.Save(ms, ImageFormat.Png)
tmpData = ms.ToArray
End Using
Return tmpData
End Function
End Class
SQLite
允许此实现的二进制密码。
- 在这种情况下,PW 的来源是一个橙色的小球图像。这导致密码为 694 字节
- 自然不可能是什么橙球,但是那个橙球
- 图像嵌入到应用程序中,因此必须在使用前将其提取 - 如果他们知道如何并且知道这就是需要做的事情。提取它的任何错误都会使它作为 PW 无效。
- 您可以通过更改该图像中的几个像素或使用不同的图像来更改密码。
- 生成的字节数组不会存储在任何地方,因此它只是暂时作为连接字符串的一部分存在。与实际连接字符串相同。
- 它不一定是图像。您可以使用
Guid.ToByteArray()
或某物的加密散列的结果。在您的代码之外重现这两者会更容易一些。
- 可以将其修改为 return 和
New SQLiteConnection
,而不是 ConnectionString,但我看不出有任何优势。
- 应用程序设置中的一个(无用的,未使用的)连接字符串可能仍会为寻找正常方法的人提供红鲱鱼。
用法
首先,在某处设置密码图像(记住,一切都是static
/Shared
):
' only place the PW source is revealed in code
SQLiteConn.PasswordImg = My.Resources.ballorange
' change path for AppData or whatever as needed
SQLiteConn.DBFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"SQLite dbs", "CryptoTest.db")
请注意,每次您引用类似 My.Resources.ballorange
的内容时,都会创建一个全新的图像对象。您只需要设置 PasswordImg
一次。如果您要更改代码以接受图像作为参数,则您 运行 有泄漏资源的风险,这是创建连接的副作用。
创建数据库
Dim tmpConnStr = String.Format("Data Source='{0}';Version=3;{1}", SQLiteConn.DBFile, "")
Dim sql = <sql>CREATE TABLE CryptoTest (
Id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
Name TEXT,
Value INTEGER);</sql>.Value
Using dbCon As New SQLiteConnection(tmpConnStr)
' tell helper to set PW, encrypt file
SQLiteConn.SetPassword(dbCon)
dbCon.Open()
Using cmd As New SQLiteCommand(sql, dbCon)
cmd.ExecuteNonQuery()
End Using
End Using
我会避免在客户端机器上创建数据库。如果它们在安装过程中提供了一个空的但加密的 DB 文件,那么它会降低修补代码以从一开始就从不加密它的难易程度。像任何其他数据文件一样分发空白,将其安装到所需路径。
虽然支持加密的 SQLite 浏览器工具并不多,因此您可能需要以上内容来应用该加密。
写入数据库
Using dbcon As New SQLiteConnection(SQLiteConn.GetLiteConnStr())
dbcon.Open()
Using cmd As New SQLiteCommand("INSERT INTO CryptoTest (name, value) VALUES ('foo', 7)", dbcon)
cmd.ExecuteNonQuery()
End Using
End Using
读取数据库
Using dbCon As New SQLiteConnection(SQLiteConn.GetLiteConnStr())
Using cmd As New SQLiteCommand("SELECT * FROM CryptoTest", dbCon)
dbCon.Open()
dtSample = New DataTable()
dtSample.Load(cmd.ExecuteReader())
End Using
End Using
dgv1.DataSource = dtSample
工作正常:
这不是万无一失的,他们可以使用 ILSpy
或其他反编译器来查看您在做什么,但 NET 应用程序总是如此。然而,这只是第一个障碍 - 他们还需要弄清楚如何获取 运行 时间数据。
当您发布 updates/bug 修复程序时,您还可以通过使用不同的图像、更改几个像素或稍微更改方法(例如将字节数组转换为 Base64 字符串)来更改密码。
它肯定比隐蔽性(连接字符串)的安全性更好,并且可能足以满足您的需求。
一些信息:
-使用SQLite加密数据库的小型应用程序
-使用 Dotfuscator Community Edition 我仍然可以查看代码内部(即使方法名称已混淆)
sQliteConnection.SetPassword("Password=ThisIsMySuperSecretPassword");
-我不需要对代码本身(逻辑)进行高度保护,但我需要保护数据库密码
如果我使用像
这样的连接PartA = "ThisIs"
PartB= "MySuper"
PartC= "SecretPassword"
Password = PartA + PartB + PartC
代码上4行不在一起,也许我可以有最低限度的保护
现在我可以更进一步了:
PartA = "Tehtibs5Iasu"
PartB= "M4ytS6uhpae3r5"
PartC= "S5efc2rhe8taP3ags5sgw4ogr5d6"
所以我有一个有效字符和一个无效字符只是为了混淆最终的潜伏者。我将使用 For 循环 "decrypt" 每个部分
这样的解决方案有多安全?
代码中还有其他保护密码的技巧吗?
Is there other tricks to protect a password inside the code?
是
(如果 'tricks' 你的意思是提供密码和使用连接字符串的替代方法)。
请注意,您不能在某人的 PC 上保密。但是特别是对于 SQLite 数据库,您可以通过不存储连接字符串来使获取连接字符串变得相当困难。演示数据库将使用密码:“
具有所有共享方法的Class用于管理连接:
Imports System.Data.SQLite
Imports System.IO
Imports System.Drawing.Imaging
Friend Class SQLiteConn
' ToDo: obscure the name to hide the purpose ?
Friend Shared PasswordImg As Image
' full path to the dbfile
Friend Shared DBFile As String
' cant create one
Private Sub New()
End Sub
' this is to avoid exposing any method which returns the PW Byte()
Friend Shared Sub SetPassword(dbcon As SQLiteConnection)
If PasswordImg Is Nothing Then
Throw New ArgumentNullException("PasswordImg")
End If
dbcon.SetPassword(ImageToByteArray(PasswordImg))
End Sub
Friend Shared Sub ChangePassword(newPW As Image)
' not tested, I think this is correct
Using dbCon As New SQLiteConnection(GetLiteConnStr())
dbCon.SetPassword(ImageToByteArray(newPW))
' to do: add error handling,
' only set pwImg on success
PasswordImg = newPW
End Using
End Sub
' the connection string is not persisted
' to make it harder to copy the byte[] ... it only
' exists momentarliy
Friend Shared Function GetLiteConnStr() As String
Dim cb As New SQLiteConnectionStringBuilder
If String.IsNullOrEmpty(DBFile) Then
Throw New ArgumentNullException("DbFile")
End If
cb.DataSource = DBFile
cb.HexPassword = ImageToByteArray(PasswordImg)
cb.Pooling = True
' add other needed options
Return cb.ConnectionString
End Function
Private Shared Function ImageToByteArray(img As Image) As Byte()
Dim tmpData As Byte()
Using ms As New MemoryStream()
img.Save(ms, ImageFormat.Png)
tmpData = ms.ToArray
End Using
Return tmpData
End Function
End Class
SQLite
允许此实现的二进制密码。
- 在这种情况下,PW 的来源是一个橙色的小球图像。这导致密码为 694 字节
- 自然不可能是什么橙球,但是那个橙球
- 图像嵌入到应用程序中,因此必须在使用前将其提取 - 如果他们知道如何并且知道这就是需要做的事情。提取它的任何错误都会使它作为 PW 无效。
- 您可以通过更改该图像中的几个像素或使用不同的图像来更改密码。
- 生成的字节数组不会存储在任何地方,因此它只是暂时作为连接字符串的一部分存在。与实际连接字符串相同。
- 它不一定是图像。您可以使用
Guid.ToByteArray()
或某物的加密散列的结果。在您的代码之外重现这两者会更容易一些。 - 可以将其修改为 return 和
New SQLiteConnection
,而不是 ConnectionString,但我看不出有任何优势。 - 应用程序设置中的一个(无用的,未使用的)连接字符串可能仍会为寻找正常方法的人提供红鲱鱼。
用法
首先,在某处设置密码图像(记住,一切都是static
/Shared
):
' only place the PW source is revealed in code
SQLiteConn.PasswordImg = My.Resources.ballorange
' change path for AppData or whatever as needed
SQLiteConn.DBFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"SQLite dbs", "CryptoTest.db")
请注意,每次您引用类似 My.Resources.ballorange
的内容时,都会创建一个全新的图像对象。您只需要设置 PasswordImg
一次。如果您要更改代码以接受图像作为参数,则您 运行 有泄漏资源的风险,这是创建连接的副作用。
创建数据库
Dim tmpConnStr = String.Format("Data Source='{0}';Version=3;{1}", SQLiteConn.DBFile, "")
Dim sql = <sql>CREATE TABLE CryptoTest (
Id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
Name TEXT,
Value INTEGER);</sql>.Value
Using dbCon As New SQLiteConnection(tmpConnStr)
' tell helper to set PW, encrypt file
SQLiteConn.SetPassword(dbCon)
dbCon.Open()
Using cmd As New SQLiteCommand(sql, dbCon)
cmd.ExecuteNonQuery()
End Using
End Using
我会避免在客户端机器上创建数据库。如果它们在安装过程中提供了一个空的但加密的 DB 文件,那么它会降低修补代码以从一开始就从不加密它的难易程度。像任何其他数据文件一样分发空白,将其安装到所需路径。
虽然支持加密的 SQLite 浏览器工具并不多,因此您可能需要以上内容来应用该加密。
写入数据库
Using dbcon As New SQLiteConnection(SQLiteConn.GetLiteConnStr())
dbcon.Open()
Using cmd As New SQLiteCommand("INSERT INTO CryptoTest (name, value) VALUES ('foo', 7)", dbcon)
cmd.ExecuteNonQuery()
End Using
End Using
读取数据库
Using dbCon As New SQLiteConnection(SQLiteConn.GetLiteConnStr())
Using cmd As New SQLiteCommand("SELECT * FROM CryptoTest", dbCon)
dbCon.Open()
dtSample = New DataTable()
dtSample.Load(cmd.ExecuteReader())
End Using
End Using
dgv1.DataSource = dtSample
工作正常:
这不是万无一失的,他们可以使用 ILSpy
或其他反编译器来查看您在做什么,但 NET 应用程序总是如此。然而,这只是第一个障碍 - 他们还需要弄清楚如何获取 运行 时间数据。
当您发布 updates/bug 修复程序时,您还可以通过使用不同的图像、更改几个像素或稍微更改方法(例如将字节数组转换为 Base64 字符串)来更改密码。
它肯定比隐蔽性(连接字符串)的安全性更好,并且可能足以满足您的需求。