如何重写VBA SQL语句以防止SQL注入?[复制]

How to rewrite VBA SQL statement to prevent SQL Injection? [duplicate]

提问人:ThomassoCZ 提问时间:8/17/2022 更新时间:8/17/2022 访问量:309

问:

我下面有这段代码。我昨天问了一个不相关的问题,有人向我指出,它对SQL注入是开放的。我做了一些研究,但我对这里到底该做什么有点迷茫。

我应该如何重写此过程以防止 SQL 注入的可能性?谢谢。如果您能为我指出正确的方向,而不是完全编写代码,我将不胜感激。

它是 MS Access VBA 中的代码,使用与 SQL Server 2019 的 ADODB 连接。

这是我在VBA中的SQL Server模块,使代码更具可读性:

Option Compare Database
Option Explicit

Private Const CONNECTION_STRING = "some random connection string"

Public Conn As ADODB.Connection

' ÚČEL FUNKCE: Spojení s SQL Server databází (bez DSN)
Public Function ConnectToServer() As String
    On Error GoTo Catch
    
    ConnectToServer = CONNECTION_STRING
    
    Exit Function
    
Catch:
    ConnectToServer = ""
    MsgBox "GetDSNLessCnnString function" & vbCrLf & vbCrLf & "Error#: " _
           & Err.Number & vbCrLf & vbCrLf & Err.Description
End Function

Public Sub Connect()

    Set Conn = New ADODB.Connection
    Conn.ConnectionString = ConnectToServer
    Conn.Open
    
End Sub

Public Sub Exec(Command As String)

    Conn.Execute Command

End Sub

Public Sub Disconnect()

    Conn.Close
    Set Conn = Nothing
    
End Sub

这是主要程序:

Private Sub cmdShipOrder_Click()

    Dim intShipmentID As Integer
    
    On Error GoTo ErrHandler

    If Me.ReservationStatus <> "ZBOŽÍ KOMPLETNĚ REZERVOVÁNO" Then
        MsgBox "Nejprve je nutné do objednávky rezervovat hmotné zboží.", vbCritical + vbOKOnly, "Chyba"
        Exit Sub
    End If
    
    If MsgBox("Bude vytvořena expedice a celá objednávka bude označena jako expedovaná. Pokračovat?", vbExclamation + vbYesNoCancel, "Upozornění") <> vbYes Then Exit Sub
    
    Connect
    
    Exec "INSERT INTO tbl1Shipments (CustomerID, ShippingMethodID, ShipToID, CarrierID, ShipmentCode, DateShipped) " & _
            "VALUES (" & Me.CustomerID & ", " & _
                    Me.ShippingMethodID & ", " & _
                    Me.ShipToID & ", " & _
                    Me.CarrierID & ", " & _
                    "'" & Year(Date) & "EXP" & Format(DCount("*", "dbo_tbl1Shipments", "ShipmentCode LIKE '%" & Year(Date) & "EXP%'") + 1, "000") & "', " & _
                    "GETDATE())"
                    
    intShipmentID = DMax("ShipmentID", "dbo_tbl1Shipments", "CustomerID=" & Me.CustomerID)
    
    Conn.BeginTrans

    Exec "INSERT INTO tbl1ShipmentDetails (ShipmentID, SalesOrderDetailID, Quantity) " & _
            "SELECT " & intShipmentID & ", SalesOrderDetailID, Quantity " & _
                "FROM v_SalesOrderSub " & _
                "WHERE SalesOrderID=" & Me.SalesOrderID

    Exec "UPDATE A " & _
            "SET ShipmentDetailID = B.ShipmentDetailID " & _
            "FROM tbl1Units A JOIN v_ShipmentSub B ON A.SalesOrderDetailID = B.SalesOrderDetailID " & _
            "WHERE B.ShipmentID = " & intShipmentID & " AND B.ProductTypeID <> 3"

    Conn.CommitTrans

    Disconnect
    
    RequeryForm ("frmSalesOrderDetails")
    RequeryForm ("frmSalesOrderList")
    
    DoCmd.OpenForm "frmShipmentDetails", , , "ShipmentID=" & intShipmentID

Exit Sub

ErrHandler:
    MsgBox "CHYBA: " & Err.Description
    Conn.RollbackTrans
    Exec "DELETE FROM tbl1Shipments WHERE ShipmentID=" & intShipmentID
    Disconnect

End Sub
sql-server vba ms-access sql 注入 ado

评论

1赞 Ike 8/17/2022
您可以使用参数而不是构建字符串:stackoverflow.com/a/10353908/16578424

答:

0赞 planetmatt 8/17/2022 #1

删除内联动态 SQL 语句,其中只需将变量注入 SQL 语句。

您可以为每个数据库操作创建存储过程,而 VB 只需将变量传递到这些过程的输入参数中。

因此,以 Delete 为例,创建一个名为“DeleteShipment”的存储过程

DROP PROC IF EXISTS dbo.sproc_DeleteShipment
GO
CREATE PROC dbo.sproc_DeleteShipment(@ShipmentID INT)
AS
BEGIN
DELETE dbo.tbl1Shipments WHERE ShipmentID = ShipmentID 
END

那么你的 VB DB 调用将更改为

Dim conn as New SqlConnection(YourConnectionString)
Dim cmd as SqlCommand = conn.createcommand
conn.open()
cmd.CommandType = CommandType.StoreProcedure
cmd.Parameters.Add(New SqlParameter("@ShipmentID ", intShipmentID)
cmd.CommandText = sproc_DeleteShipment
cmd.ExecuteNonQuery() 
conn.close()

从理论上讲,您的代码对 SQL 注入是开放的,但仅从该示例来看,您的所有变量都是 INT,这使得它变得更加困难。但是,如果您的货件编号是一个字符串,并且黑客设法将字符串“1 OR 1=1”获取到货件编号中,则整个表将被删除。

如果找到相同的字符串进入 SPROC 的输入参数,则不会发生这种情况。

评论

1赞 ThomassoCZ 8/17/2022
谢谢。老实说,我 99% 的参数都是主键,即 INT IDENTITY(1,1),用户不会输入类似的东西。它将是一个小型公司信息系统,位于内部封闭的安全服务器上,最多只能由5人通过MS Access和Active Directory身份验证访问。这就是为什么我犹豫要不要处理这个问题,因为对于我的情况来说,这似乎太复杂了。你觉得怎么样?
1赞 planetmatt 8/17/2022
这是一个判断,称为TBH。您必须权衡数据丢失的成本和额外开发的成本。有人访问该系统的可能性有多大?如果他们这样做了并且数据丢失,恢复的难易程度如何?如果您无法恢复,那么企业的材料成本是多少?
1赞 braX 8/17/2022
@ThomassoCZ 就你而言,我会同意你的看法。
1赞 planetmatt 8/17/2022
如果您定期进行 SQL 备份,能够快速恢复这些备份,并且恢复备份时的停机时间对企业来说是可以接受的,我会跳过额外的工作。
0赞 ThomassoCZ 8/17/2022
是的,我当然计划每天备份SQL Server。谢谢你们,我想我现在会跳过这个。