处理 VB.NET 中的 varbinary 字段
Posted
技术标签:
【中文标题】处理 VB.NET 中的 varbinary 字段【英文标题】:Dealing with a varbinary field in VB.NET 【发布时间】:2009-06-10 16:32:59 【问题描述】:我们的一个合作伙伴正在调用一个包含名为 token 的参数的 Web 服务。令牌是两个数字的 MD5 散列的结果,它帮助我们使用我们的合作伙伴系统对用户进行身份验证。我们的合作伙伴向用户询问两个字符串,将它们连接起来,通过 MD5 运行它们,然后调用我们的 Web 服务。 MD5的结果就是token,以字符串的形式提交给我们。
我们将有效令牌存储在数据库中 - 因为我们使用 SQL Server 来计算我们端的令牌,SQL 似乎最乐意将令牌存储为 varbinary,这是 MD5 计算的本机结果。
我们有两段代码尝试做同样的事情 - 运行一个选择查询,该查询根据提交的令牌提取一个值。一个使用动态查询(这是一个问题),但它有效。另一个尝试以参数化(更安全)的方式做同样的事情,它不起作用 - 它无法找到令牌。
这是两个相互竞争的尝试。一、失败的参数化版本:
byteArrayToken = System.Text.UnicodeEncoding.Unicode.GetBytes(stringToken)
scSelectThing.CommandText = "select thing from tokenstable where token=@token"
Dim param As SqlParameter = scSelectThing.Parameters.Add("@token", SqlDbType.VarBinary)
param.Value = byteArrayToken
lbOutput2.Text = scSelectThing.ExecuteScalar()
其次,有效的动态查询字符串版本:
Dim scSelectThing As New SqlCommand
scSelectThing.CommandText = "select thing from tokenstable where token=convert(varbinary, " + stringToken + " )"
lbOutput2.Text = scSelectThing.ExecuteScalar()
当我们运行 SQL 分析器时,这就是实际对 DB 执行的操作:
exec sp_executesql N'select thing from tokenstable where token=@token',N'@token varbinary(68)',@token=0x3000780046003800380034004100450036003400430038003300440033004100380034003800460046004300380038004200390034003400330043004200370042004600
这对我来说看起来不对,看起来好像我们正在做的事情会导致堆栈中的某些东西在某处进行错误的转换。
有什么想法吗?使用动态查询启动显然是不可接受的。
编辑:
字符串是一个 MD5 哈希结果。为了让它在查询分析器中工作,我们这样做:
select * from tokenstable where
token=convert(varbinary, 0xF664AE32C83D3A848FFC88B9443CB7BF )
请注意缺少引号,如果我们引用它,查询将失败。我们要比较的字段是 varbinary,SQL Server 存储了我们端的 MD5 计算结果。
【问题讨论】:
答案已更新...您需要先从十六进制转换为字节数组。 【参考方案1】:您的问题可能是字符串->二进制转换使用不同的编码。尝试使用System.Text.Encoding.ASCII
而不是Unicode
,看看这是否对你有用。我的猜测是 convert()
认为您的字符串是 varchar
而不是 nvarchar
并且使用 ASCII 而不是 Unicode 进行自己的字符串->二进制转换。
编辑
另外,这个字符串是等效于哈希的实际二进制,还是十六进制表示?
编辑 2
那么您的问题是您正在传递二进制数据的十六进制表示的二进制表示。够迷惑了吧?
您只需将十六进制 string
转换为 byte
数组,然后再将其添加为参数值。您可以使用以下代码来做到这一点,取自this question 的答案(并翻译为 VB.NET):
Public Shared Function StringToByteArray(ByVal hex As String) As Byte()
Dim NumberChars As Integer = hex.Length
Dim bytes(NumberChars / 2) As Byte
For i As Integer = 0 To NumberChars - 1 Step 2
bytes(i / 2) = Convert.ToByte(hex.Substring(i, 2), 16)
Next
Return bytes
End Function
所以你的代码看起来像这样......
byteArrayToken = StringToByteArray(stringToken)
scSelectThing.CommandText = "select thing from tokenstable where token=@token"
Dim param As SqlParameter = scSelectThing.Parameters.Add("@token", SqlDbType.VarBinary)
param.Value = byteArrayToken
lbOutput2.Text = scSelectThing.ExecuteScalar()
【讨论】:
虽然存储为 varbinary,但我们拥有的输入字符串是从 php 的 md5() 返回的十六进制表示。以上是关于处理 VB.NET 中的 varbinary 字段的主要内容,如果未能解决你的问题,请参考以下文章
从 VB.NET 查询 Access 数据库中的 Yes/No 字段
将图像上传到 sql server 上的 varbinary 字段时,file_get_contents 值中的“附近语法不正确”