【问题标题】:How to make sql string safe in vb.net without using parameters如何在不使用参数的情况下在 vb.net 中使 sql 字符串安全
【发布时间】:2021-02-03 21:24:08
【问题描述】:

我正在处理一个用vb.net 编写的项目,该项目有sql innjection 问题,我几乎使用parameters 修复了所有注入,有一种情况是构建sql 字符串然后加密并传递给viewState , 之后会从viewState 取回解密后运行,这种情况下显然不能使用params,也不能重构为在viewState 中不传递sql,唯一的选择就是在构建sql时避免注入尽可能多地声明,或者使用参数然后获取生成的sql语句并将其传递给查看状态。

参数值由字符串和数字混合而成。

例如

 sSQL = sSQL & " WHERE Name LIKE '" & lstBrowse.SelectedItem.Value & "%'"

 sSQL = sSQL & " WHERE State ='" & lstBrowse.SelectedItem.Value & "'"

 sSQL = sSQL & " WHERE OrganizationID=" & lstBrowse.SelectedItem.Value

如何在不使用参数的情况下做到这一点?我应该考虑和避免什么?

【问题讨论】:

  • 那么是不是不可能在你的视图状态中存储一个参数化的查询,然后在执行它时,在那里设置它的值?
  • 为什么不能在SQL代码中使用参数,同时将参数值添加到ViewState中?然后你在解密后两者都有,所以你可以创建一个命令并添加参数。
  • 我认为发帖人没有意识到您可以构建 sql 字符串,而是使用参数动态构建它们,从而获得参数安全的 sql。我在下面的帖子中解释了如何。真的公平吗?我认为可以将一个 sql 命令对象推入会话,因为该对象包含您的 sql,包含您的参数,并且它只有一个对象。您甚至可以在该 sql 命令中保存连接对象。所以它相当不错。
  • 您必须通过Stored ProcedureParameterized Query 执行此操作。否则你必须创建自定义函数来删除可疑字符,但是当你已经为你构建了它时,不建议再次发明轮子。
  • 在这种情况下显然不能使用参数 - 在极少数情况下 SQL 无法参数化,我向你保证这不是其中之一

标签: c# asp.net .net vb.net sql-injection


【解决方案1】:

好的,我认为问题在于假设您不能有“可选”参数,或者您必须提前设置它们。 (你没有)。

你可以去列出这个:

dim strWhere  as string
strWhere = "(State =  @State)
cmdSQL.Parmaters.Add("@State",SqlDbType.NVarchar).Value = lstBrowse.SelectedItem.Value 

现在,我可以“即时”向 strWhere 添加更多条件,并且随着时间的推移将参数添加到 cmdSQL.Parmaters 集合中。

现在,假设你在一些复杂的网格页面上,用户选择了一些东西,现在你需要把这个说传递给另一个表单吗?

Well, it gets a wee bit messy to have:
Keep track of some field names
Keep track of some conditions (=, like, etc.)
Keep track of the parameters

但您当然可以将一个参数列表和一些也匹配该参数的 sql“串”在一起。因此无需使用 EXISTING 参数对 sql 进行硬编码。

现在,另一个问题是您建议不仅要构建一些动态 sql,而且您需要在会话中传递它(或者您想要那种能力)。

好吧,我只想构建一个非常短代码的“集群”,将以上所有内容放入一个非常短且简单的类中。然后将该类 SHOVE 到会话中。

因此,将这一点代码放入项目中的一个标准代码模块中。

公共类 SqlParms

    Public cmdSQL As New SqlCommand("", GetCon)
    Public Where As String
    Private m_SQL As String

    Public Sub Add(FieldName As String, Cond As String, FieldValue As Object, Datatype As SqlDbType)
        Dim mycond As String
        Dim prex As String = "", sufx As String = ""
        If Left(Cond, 1) = "%" Then prex = "'%' + "
        If Right(Cond, 1) = "%" Then sufx = " + '%'"
        mycond = Replace(Cond, "%", "")

        If Where <> "" Then Where += " AND "
        Where += "(" & FieldName & " " & mycond & " " & prex & "@" & FieldName & sufx & ")"
        cmdSQL.Parameters.Add("@" & FieldName, Datatype).Value = FieldValue

    End Sub

    Public Property SQL As String
        Get
            Return m_SQL
        End Get
        Set(value As String)
            m_SQL = value & " WHERE " & Where
            cmdSQL.CommandText = m_SQL
        End Set
    End Property

End Class

那么,以上所有内容都可以吗?让您添加一个“字段”、一个“条件”,然后再添加一些。 很简单。

所以,现在在代码中,我可以走了:

Dim MyParms As New SqlParms
Session("MyParms") = MyParms

现在,请注意我们曾经将 session 指向该类?然后我可以在当前的代码位中添加/修改,而​​不必将 MyParms 汇集/保存/推回 - 它是一个对象,现在它在会话中。

所以,让我们添加你的条件。

MyParms.Add("State", "=", lstBrowse.SelectedItem.Value, SqlDbType.NVarChar)

好的,所以上面不仅添加了,而且在我们的会话中也添加了!!!

好的,假设我们有两个条件,第二个是 ContactID(数据库中的 PK 值 - 因此是整数数据类型)。 好的,我们现在开始:

MyParms.Add("OrganziationID", "=", lstBrowse.SelectedItem.Value, SqlDbType.Int)

或许

MyParms.Add("OrganziationID", "=", droplist1.SelectedValue, SqlDbType.Int)

MyParms.SQL = "SELECT * from tblHotels"

再次:运行上述 1 或 2 条件后的注意事项?它在 session() 中。

好吧,假设我们跳转到了一个新的不同页面。现在我们需要填充一个网格。

代码将是:

请注意下面我们如何不使用新关键字非常非常小心!

    Dim MyParms As SqlParms = Session("MyParms")
    Dim rst As New DataTable
    Using MyParms.cmdSQL
        MyParms.cmdSQL.Connection.Open()
        rst.Load(MyParms.cmdSQL.ExecuteReader)
    End Using

    GridView1.DataSource = rst
    GridView1.DataBind()

因此,这个小“帮助”例程可以让您构建 where 子句。 它在 session() 中,现在您可以将所有这些内容传递/跳转到另一个页面。

另一件非常有趣但人们常常没有意识到的事情? 您始终可以向 sql 命令对象添加参数,但尚未设置 sql 集。你甚至不需要连接集。

所以,您实际上可以转储上述“帮助程序”例程,并创建一个 sql 命令对象,然后将其推送到会话中。

不管上面的?您不必对 sql 进行预硬编码。这些值可以并且将成为参数安全的(sql 注入安全),即使您要添加“可选”参数,这也适用。唯一的技巧是确保您还使用这些可选参数构建 sql。

所以,如果我这样去:

dim MyParms as new SqlParms
MyParms.Add("City", "Like%", "E", SqlDbType.NVarChar)
MyParms.SQL = "SELECT * from tblHotels"
Dim rst As New DataTable
    Using MyParms.cmdSQL
        MyParms.cmdSQL.Connection.Open()
        rst.Load(MyParms.cmdSQL.ExecuteReader)
    End Using

    GridView1.DataSource = rst
    GridView1.DataBind()

所以上面的内容会用结果表填充我们的数据网格。

上面的sql现在是这样的:

SELECT * from tblHotels WHERE (City Like @City + '%')

现在是因为我想要“点赞”支持吗?好吧,我无法在参数名称中添加/包含/包含 %(我使用与前面带有 @ 的字段名称相同。

所以,我使用 %like(作为前缀通配符) 和 Like%(用于后缀)。然后代码会去掉 % 并将其正确添加到上面的 where 子句中。

因此,您可以/可以在“添加”更多条件时对字符串进行编码。但在所有情况下,使用参数仍然不仅是个好主意,而且做起来也不是那么难。

我在那个类中还使用了一个名为 GetCon 的公共函数,它只返回一个连接对象,但您可以将该类中的“GetCon”替换为您自己的例程,该例程返回一个连接字符串,然后用于创建 sqlconneciton对象。

另外,相当次要,但我确实假设 sql 属性设置为 LAST,因为 sql 字符串随后与 where 子句组合。如果添加更多参数,则需要重新设置 sql 属性。

总结: 您可以并且应该添加附加值作为参数。我没有太多理由不这样做。

如果您需要在一个页面中设置所有这些,然后跳转到另一个页面,那么可以将这个可爱的帮助程序推入会话中。 (或者甚至让当前页面允许说一些额外的过滤。

【讨论】:

  • 感谢@albert 花时间写了一个全面的答案,我明白你在说什么,但不幸的是我不允许重构代码来改变 sql 语句传递给 viewState 的方式跨度>
  • 您可以使用简单的数组或集合。如果您不允许使用连接用户输入的 sql 字符串更改某些字符串会话 var,那么您不能对可能的 sql 注入场景负责。代替上述帮助程序,您可以使用单个 sqlcommand 对象,并简单地向其中添加参数。非常棒的是,您永远不必知道甚至决定是否需要在值(对于字符串)、数字(无引号)周围加上引号。约会?您不必担心格式和引号(痛苦)。只是一个简单的直接 var 分配,没有混乱的连接。
  • 所以代替viewstate中的sql字符串,创建一个sql命令对象。它具有可以在现有代码中大量使用的 sql 字符串(命令文本),并且它具有内置的参数集合。太好了,您不必担心日期格式或任何引号。即使对于 datetime var 中的日期值,您也可以将“分配”作为参数 - 无需担心格式错误,也无需再考虑是否有或是否添加引号。它只是用简单的 var 赋值来清理代码。归根结底,以上表明即使是动态的 sql 代码也是可能的。
猜你喜欢
  • 1970-01-01
  • 2016-01-17
  • 1970-01-01
  • 2018-02-14
  • 1970-01-01
  • 1970-01-01
  • 2014-04-23
  • 2017-02-18
  • 1970-01-01
相关资源
最近更新 更多