Can my users inject my dynamic sql?
我是为内部用户编写的桌面开发人员,所以我不担心恶意黑客,但我想知道他们在更新将在服务器上执行SQL的值时是否可以输入任何内容。
业务定义了它们的内容架构,我为它们提供了一个CRUD应用程序,当它们的架构更改时,不必更改该应用程序,因为验证详细信息是表驱动的,更新是使用动态SQL的。我必须在它们的数据输入中支持单引号,所以当它们输入时,我会在服务器上执行SQL之前将它们加倍。然而,根据我读到的,这不足以停止注射。
所以我的问题是,他们可以在一个自由格式的文本字段中输入什么文本,这个字段可以更改服务器上的某些内容,而不是存储为文本值?
基本上,我在运行时构建的SQL语句遵循以下模式:
更新表集字段=值,其中pkfield=pkval
使用此vb.net代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | Friend Function updateVal(ByVal newVal As String) As Integer Dim params As Collection Dim SQL As String Dim ret As Integer SQL = _updateSQL(newVal) params = New Collection params.Add(SQLClientAccess.instance.sqlParam("@SQL", DbType.String, 0, SQL)) Try ret = SQLClientAccess.instance.execSP("usp_execSQL", params) Catch ex As Exception Throw New Exception(ex.Message) End Try Return ret End Function Private Function _updateSQL(ByVal newVal As String) As String Dim SQL As String Dim useDelimiter As Boolean = (_formatType = DisplaySet.formatTypes.text) Dim position As Integer = InStr(newVal,"'") Do Until position = 0 newVal = Left(newVal, position) + Mid(newVal, position) ' double embedded single quotes ' position = InStr(position + 2, newVal,"'") Loop If _formatType = DisplaySet.formatTypes.memo Then SQL ="declare @ptrval binary(16)" SQL = SQL &" select @ptrval = textptr(" & _fieldName &")" SQL = SQL &" from" & _updateTableName & _PKWhereClauses SQL = SQL &" updatetext" & _updateTableName &"." & _fieldName &" @ptrval 0 null '" & newVal &"'" Else SQL ="Update" & _updateTableName &" set" & _fieldName &" =" If useDelimiter Then SQL = SQL &"'" End If SQL = SQL & newVal If useDelimiter Then SQL = SQL &"'" End If SQL = SQL & _PKWhereClauses End If Return SQL End Function |
当我将文本字段更新为值时
Redmond'; drop table OrdersTable--
它产生:
1 | Update caseFile set notes = 'Redmond''; drop table OrdersTable--' where guardianshipID = '001168-3' |
并将值更新为输入的文字值。
他们还可以输入什么来注入SQL?
再说一次,我不担心有人想在他们的工作中攻击服务器,但我想知道如果他们不小心从其他地方粘贴了文本并破坏了一些东西。
谢谢。
您还可以评估其他解决方案。使用参数动态生成SQL。像这样:
1 2 3 4 5 6 7 8 9 10 | // snippet just for get the idea var parameters = new Dictionary<string, object>(); GetParametersFromUI(parameters); if (parameters.ContainsKey("@id")) { whereBuilder.Append(" AND id = @id"); cmd.Parameters.AddWithValue("@id", parameters["@id"]); } ... |
无论您如何清理用户输入,增加攻击面都是您所做工作的真正问题。如果回顾一下SQL注入的历史,您会发现,随着时间的推移,新的、甚至更具创造性的方法已经出现了,它们会造成巨大的破坏。虽然您可能已经避免了已知的代码,但它总是潜伏在转角处,这使得这种类型的代码很难产生。你最好使用不同的方法。
您永远不会希望使用将直接执行的用户输入来构建SQL语句。正如您所发现的,这会导致SQL注入攻击。正如您所描述的,对于某人来说,在您的数据库中删除一个表是很简单的。
您希望使用参数化查询,其中使用值的占位符构建SQL字符串,然后将这些参数的值传入。
使用vb,你可以做如下的事情:
1 2 3 4 5 6 7 8 9 10 11 12 | 'Define our sql query' Dim sSQL As String ="SELECT FirstName, LastName, Title" & _ "FROM Employees" & _ "WHERE ((EmployeeID > ? AND HireDate > ?) AND Country = ?)" 'Populate Command Object' Dim oCmd As New OledbCommand(sSQL, oCnn) 'Add up the parameter, associated it with its value' oCmd.Parameters.Add("EmployeeID", sEmpId) oCmd.Parameters.Add("HireDate", sHireDate) oCmd.Parameters.Add("Country", sCountry) |
(这里举的例子)(我也不是一个VB程序员,所以这可能不是正确的语法,但它得到了重点)
唯一安全的假设是,如果您不使用参数化查询(并且您不完全使用这里的查询,因为您要将输入字符串连接到SQL中),那么您就不安全。
和加倍代码一样难看(:p-try-string.replace),我很肯定这能解决问题。
假设您转义字符串文本(从您所说的操作中),那么您应该是安全的。我唯一能想到的是,如果使用基于Unicode的字符集与数据库通信,请确保发送的字符串在该编码中有效。