SQL 即使在转义引号时也会注入
SQL Injection even when escaping quote
我正在想办法解决以下问题,因为看起来有人这样做了,我想修复它。但是,在用 OWASP Recommendation
之类的东西修复它之前,我真的很想了解攻击是如何工作的
Set conn = Server.CreateObject("ADODB.Connection")
conn.open xDb_Conn_Str
sSql = "SELECT * FROM [User]"
sSql = sSql & " WHERE [Username] = '" & CleanSql(sUserId) & "'"
Set rs = conn.Execute(sSql)
CleanSql -
Function CleanSql(str)
Dim sWrk
sWrk = Trim(str&"")
sWrk = Replace(sWrk, "'", "''") ' Adjust for Single Quote
sWrk = Replace(sWrk, "[", "[[]") ' Adjust for Open Square Bracket
CleanSql = sWrk
End Function
这里明显转义了单引号
在此之后,它会立即检查是否发现用户使用以下内容验证密码:
If UCase(rs("Password")) = UCase(sPassWd) Then
DoStuff()
感谢任何帮助。
你应该总是使用Prepared statement,因为在大多数情况下转义是不够的,因为总是有你会忘记的特殊情况。
Dim cmdPrep1 As New ADODB.Command
Set cmdPrep1.ActiveConnection = conn
cmdPrep1.CommandText = "SELECT * FROM [User] WHERE [Username] = ?"
cmdPrep1.CommandType = adCmdText
cmdPrep1.Prepared = True
Set prm1 = cmdPrep1.CreateParameter("Username", adChar, adParamInput, Len(sUserId), sUserId)
cmdPrep1.Parameters.Append prm1
Set rs = cmdPrep1.Execute()
如果准备好的语句对您的语言或数据库库不可用,强烈考虑切换。
请参阅此 wikipedia article 了解为什么准备好的语句更安全,但其要点是参数与查询分开传递,因此 避免在查询中嵌入不受信任的字符串 。
既然你已经知道prepared/parameterized语句的好处,我就不多说了。您似乎只是好奇您现有的应用程序是如何被破坏的。
一个简单的 \' ; drop table users --
就可以打败你的报价加倍。您的 CleanSql()
函数会将其变成:
\'' ; drop table users --
您的 SQL 语句将变为:
... WHERE [Username] = '\'' ; drop table users --'
并且由于 '\''
是一个有效值(转义单引号),您的 where
子句实际上已结束。 ;
开始一个新命令,--
有效地注释掉结束引号。 drop table
可以是任何东西... update users set password=...
或 insert into users values ()
或攻击者想要 运行.
的任何东西
一个简单的方法:var = Replace(Request.Form("form"),"'","\'")
只是因为这在 the ESCAPE
keyword is used.
时不起作用
此外,您的 CleanSql
函数不适用于未加引号的值(例如数值)。
这就是为什么建议使用参数化查询的原因 - 这些查询将值视为数据而不是查询的一部分。
有时您不能使用参数化,例如,如果您动态更改 ORDER BY
或者如果您想动态更改从中读取数据的 table。在这些情况下,您应该使用白名单来确保您的应用程序允许动态数据。不能使用参数化的另一种情况是存在 IN
子句时。这是您的 CleanSql
函数有用的地方 - 请注意您不需要括号转义 - 这仅适用于未指定转义字符的 LIKE
查询。
我正在想办法解决以下问题,因为看起来有人这样做了,我想修复它。但是,在用 OWASP Recommendation
之类的东西修复它之前,我真的很想了解攻击是如何工作的 Set conn = Server.CreateObject("ADODB.Connection")
conn.open xDb_Conn_Str
sSql = "SELECT * FROM [User]"
sSql = sSql & " WHERE [Username] = '" & CleanSql(sUserId) & "'"
Set rs = conn.Execute(sSql)
CleanSql -
Function CleanSql(str)
Dim sWrk
sWrk = Trim(str&"")
sWrk = Replace(sWrk, "'", "''") ' Adjust for Single Quote
sWrk = Replace(sWrk, "[", "[[]") ' Adjust for Open Square Bracket
CleanSql = sWrk
End Function
这里明显转义了单引号
在此之后,它会立即检查是否发现用户使用以下内容验证密码:
If UCase(rs("Password")) = UCase(sPassWd) Then
DoStuff()
感谢任何帮助。
你应该总是使用Prepared statement,因为在大多数情况下转义是不够的,因为总是有你会忘记的特殊情况。
Dim cmdPrep1 As New ADODB.Command
Set cmdPrep1.ActiveConnection = conn
cmdPrep1.CommandText = "SELECT * FROM [User] WHERE [Username] = ?"
cmdPrep1.CommandType = adCmdText
cmdPrep1.Prepared = True
Set prm1 = cmdPrep1.CreateParameter("Username", adChar, adParamInput, Len(sUserId), sUserId)
cmdPrep1.Parameters.Append prm1
Set rs = cmdPrep1.Execute()
如果准备好的语句对您的语言或数据库库不可用,强烈考虑切换。
请参阅此 wikipedia article 了解为什么准备好的语句更安全,但其要点是参数与查询分开传递,因此 避免在查询中嵌入不受信任的字符串 。
既然你已经知道prepared/parameterized语句的好处,我就不多说了。您似乎只是好奇您现有的应用程序是如何被破坏的。
一个简单的 \' ; drop table users --
就可以打败你的报价加倍。您的 CleanSql()
函数会将其变成:
\'' ; drop table users --
您的 SQL 语句将变为:
... WHERE [Username] = '\'' ; drop table users --'
并且由于 '\''
是一个有效值(转义单引号),您的 where
子句实际上已结束。 ;
开始一个新命令,--
有效地注释掉结束引号。 drop table
可以是任何东西... update users set password=...
或 insert into users values ()
或攻击者想要 运行.
一个简单的方法:var = Replace(Request.Form("form"),"'","\'")
只是因为这在 the ESCAPE
keyword is used.
此外,您的 CleanSql
函数不适用于未加引号的值(例如数值)。
这就是为什么建议使用参数化查询的原因 - 这些查询将值视为数据而不是查询的一部分。
有时您不能使用参数化,例如,如果您动态更改 ORDER BY
或者如果您想动态更改从中读取数据的 table。在这些情况下,您应该使用白名单来确保您的应用程序允许动态数据。不能使用参数化的另一种情况是存在 IN
子句时。这是您的 CleanSql
函数有用的地方 - 请注意您不需要括号转义 - 这仅适用于未指定转义字符的 LIKE
查询。