提问人:ThomassoCZ 提问时间:8/17/2022 更新时间:8/17/2022 访问量:309
如何重写VBA SQL语句以防止SQL注入?[复制]
How to rewrite VBA SQL statement to prevent SQL Injection? [duplicate]
问:
我下面有这段代码。我昨天问了一个不相关的问题,有人向我指出,它对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
答:
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。谢谢你们,我想我现在会跳过这个。
评论