这段代码可以防止SQL注入吗?
-
05-07-2019 - |
题
背景
我已签约分析现有数据提供者,并且我知道以下代码有错误;但为了指出它有多糟糕,我需要证明它容易受到 SQL 注入的影响。
问题
什么“Key”参数可能会破坏 PrepareString
函数并允许我执行 DROP
陈述?
代码片段
Public Shared Function GetRecord(ByVal Key As String) As Record
Dim Sql As New StringBuilder()
With Sql
.Append("SELECT * FROM TableName")
If String.IsNullOrEmpty(Agency) Then
.Append(" ORDER BY DateAdded")
Else
.Append(" WHERE Key = '")
.Append(PrepareString(Key))
.Append("'")
End If
End With
Return ExecuteQuery(Sql.ToString())
End Function
Public Shared Function PrepareString(ByVal Value As String) As String
Return Value.Replace("''", "'") _
.Replace("'", "''") _
.Replace("`", "''") _
.Replace("´", "''") _
.Replace("--", "")
End Function
解决方案
回答直接问题:此代码是否阻止SQL注入:否
这是证明 - 通过PrepareString方法推送此字符串:
Dim input = "'" & Chr(8) & "; Drop Table TableName; - " & Chr(8) & "-"
Dim output = PrepareString(input)
Console.WriteLine(input)
Console.WriteLine(output)
我修改了您发布的GetRecord方法,以返回完全准备好的SQL字符串,而不是从数据库中获取记录:
Console.WriteLine(GetRecord(output))
这是输出
Input = ; Drop Table TableName; --
Output = '; Drop Table TableName; --
Query = SELECT * FROM TableName WHERE Key = ''; Drop Table TableName; --'
添加1行额外代码:
My.Computer.Clipboard.SetText(input)
您已将需要复制的字符串复制到剪贴板上以粘贴到网站上的输入字段中以完成SQL注入:
'; Drop Table TableName; - -
[注意到StackOverflow从输出中省略了控制字符,因此您必须按照代码示例创建输出]
在运行PrepareString方法之后,它将具有完全相同的输出 - Chr(8)ASCII代码是退格,它将删除额外的“'”。你附加到我的将关闭你的字符串,然后我可以自由地添加我想要的任何东西。你的PrepareString没有看到我 - 因为我实际上正在使用 - 带有退格符来删除空格。
您正在构建的结果SQL代码将不受阻碍地执行我的Drop Table语句,并立即忽略您的其余查询。
有趣的是,您可以使用不可打印的字符基本上绕过您可以发明的任何字符检查。所以使用参数化查询是最安全的(这不是你提出的问题,但是避免这种情况的最佳途径)。
其他提示
要回答你可疑的问题,不会有用。
.Replace("``","''")
会阻止合法查询'''
.Replace("´","''")
会阻止合法查询“´”
.Replace(" - ","")
会阻止带有“ - ”的合法查询
.Replace("''","'")
会错误地修改包含''''的合法查询
等等。
此外,完整的转义字符集可以在一个RDBMS之间变化。参数化查询FTW。
我认为如果你只是替换'with''是不可能的。我听说可以更改转义字符,这可能会打破这个,但我不确定。我觉得你很安全。
我认为它是安全的(至少在SQL服务器中),我认为你真正需要做的唯一事情是 s = s.Replace("'","''") 代码>。当然你应该使用参数化查询,但你已经知道了。
这 MSDN 文章 涵盖了您需要注意的大部分内容(恐怕在涉及 SQL 注入时会说所有内容)。
但我会回应其他人对参数参数参数的看法。
至于你的例子,有一些陷阱[编辑:更新了这些]:
字符串“1 OR 1=1”不允许用户取回所有内容吗或者更糟“1;删除表某个表名”
根据您要检查的文章:
;- 查询分隔符。
' - 字符数据字符串分隔符。
-- - 注释分隔符。
/* ... / - 注释分隔符。文字 /之间 */未由服务器评估。
XP_-在目录扩展的存储过程的名称的开头(例如XP_CMDShell)使用。
如果你尝试使用你的代码,有些人可以传递一个密钥(;从表中选择*;获取他们想要的表格列表。
在你的代码中你不检查分号,它允许你结束一个t-sql语句并启动另一个。
我会使用参数化查询。