将
txtTagNumber
作为查询参数传递SqlCommand cmd = new SqlCommand("INSERT INTO dbo.Cars " +"VALUES(@TagNbr);" , conn);
cmd.Parameters.Add("@TagNbr", SqlDbType.Int);
cmd.Parameters["@TagNbr"].Value = txtTagNumber.Text;
在构造查询之前将
txtTagNumber
转换为整数int tagnumber = txtTagNumber.Text.ToInt16(); /* EDITED */
INSERT into Cars values(tagnumber.Text); /* then is it the same? */
此外,这里我将使用正则表达式验证来停止插入非法字符。
#1 楼
参数化查询在运行SQL查询之前会对参数进行适当的替换。它完全消除了“脏”输入更改查询含义的可能性。也就是说,如果输入包含SQL,则该输入将不会成为执行内容的一部分,以防SQL永远不会注入到结果语句中。评论
@sqlchild:表,列或过程名称(通常为孔标识符)无法参数化,只能“值”或“参数”(如OJ所说)。像在WHERE或JOIN / IN子句中使用的那样,函数或过程的参数等等。因此,名称为“参数化”查询。
– Christian.K
2011-3-29在6:12
@ Christian.K:先生,我的意思是,如果我在文本框中将DROP表Cars传递给insert语句,则将其插入cars values(@carname);中。 cmd.Parameters.Add(@ carname,SQLDBTYPE varchar),那么参数化查询将做什么?
–sqlchild
2011-3-29在6:20
@sqlchild:对不起,那是误会了。它将只在相应的列/字段中插入字符串“ DROP table Cars”。
– Christian.K
2011-3-29在6:23
@sqlchild:不,它不被称为转义。数据库提供了一种机制,可以避免转义。我认为您需要阅读更多有关SQL注入的背景知识(例如,在此处en.wikipedia.org/wiki/SQL_injection)-而不是在评论中或对原始问题的答复中。
– Christian.K
2011年3月29日在7:11
@sqlchild:您开始改变话题,并且已经接受了原始问题的答案。请考虑发布另一个/新问题,以了解您需要了解的其他事情。 SO应该这样工作,并且可以提高发现能力并使每个人都受益。
– Christian.K
2011年3月29日在7:34
#2 楼
当可能的参数中包含sql并且未按原样处理字符串时,就会发生sql注入。例如:
var sqlquerywithoutcommand = "select * from mytable where rowname = '" + condition+''";
条件是来自请求中用户的字符串。如果条件是恶意的
,例如:
var sqlquerywithoutcommand = "select * from mytable where rowname = '" + "a' ;drop table mytable where '1=1"+"'";
您可能最终会运行恶意脚本。
,但是使用参数输入清除所有可能转义字符串字符的字符...
可以确保无论出现什么内容都将无法运行注入脚本。
使用具有实际执行sql的参数的命令对象看起来像这样
select * from mytable where rowname = 'a'';drop table mytable where 1=1'''
因为它会寻找具有rowname = a'; drop table mytable的行,其中1 = 1'
,并且不运行其余脚本
评论
但是当sql从参数中获取值时,它是如何读取的,我的意思是它将以与直接从字符串中获取值相同的方式获取它,即它将其读取为drop table mytable,还是我错了?
–sqlchild
2011-3-29在6:13
@ sqlchild:nope ...它转义了所有的'和',以便整个字符串成为参数...让我将其添加到答案中
–Mulki
2011-3-29在6:16
#3 楼
想象一下动态SQL查询
sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND
Pass=' + password
因此,简单的sql注入只是将Username输入为
' OR
1=1--
,这将有效地进行sql查询:sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS='
+ password
这表示选择所有其用户名为空('')或
1 = 1(布尔值,等于true)的客户。然后使用-注释掉其余的查询。因此,这只会打印出所有
客户表,或执行您想做的任何事情,如果登录,它
将使用第一个用户的特权登录,该特权通常是
管理员。
现在,参数化查询的方式有所不同,例如:
sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?'
parameters.add(“ User”,username)参数。 add(“ Pass”,password)
其中用户名和密码是指向关联的变量
输入的用户名和密码
现在,您可能已经认为,这完全不会改变
。当然,您仍然可以只在用户名字段中放入
Nobody OR 1 = 1'-之类的东西,有效地进行查询:
sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND
Pass=?'
这样,似乎是一个有效的论点。但是,您会错了。
参数化查询的工作方式是sqlQuery作为
查询发送,并且数据库确切知道此查询将执行的操作,并且
才将用户名和密码仅作为值插入。
这意味着它们不能影响查询,因为数据库已经
知道查询将执行什么操作。因此,在这种情况下,它将查找
"Nobody OR 1=1'--"
的用户名和空白密码,该密码应该为false。来源:lavamunky.com; 2011年11月
#4 楼
参数化查询可以处理所有问题-为什么会出问题?使用参数化查询,除了常规注入外,您还可以处理所有数据类型,数字(整数和浮点数),字符串(带有嵌入式引号) ,日期和时间(当不使用不变的区域性不调用.ToString()且您的客户端移动到日期格式意外的计算机上时,没有格式问题或本地化问题)。评论
他们肯定会处理SQL注入,但不会处理其他类型的注入(主要是JavaScript等网络端注入)。
– dvhh
2011-3-29在6:12
#5 楼
参数化查询允许客户端从查询文本中分别传递数据。在大多数没有文本的地方,您都可以进行验证+转义。
当然,参数化无助于其他类型的注入,但是因为参数是分别传递的,所以它们不用作执行文本查询。
一个很好的类比是大多数现代处理器和操作系统使用的“最近”执行位,以防止缓冲区溢出。它仍然允许缓冲区溢出,但阻止执行注入的数据。
#6 楼
完全可以理解为什么会这样。sqlQuery = "select * from users where username='+username+';"
vs
sqlQuery = "select * from users where username=@username;"
以上两个查询似乎都
前者使用输入进行查询,后者决定查询,但仅在执行查询时替换输入。
更清楚地说,参数的值位于堆栈中存储变量内存的位置,并在需要时用于搜索。
如果我们要将
' OR '1'='1
作为用户名中的输入,前者将动态构造一个新查询或作为sql查询字符串sqlQuery
的一部分的查询,然后执行该查询。在同一输入上,后者将搜索对于
' OR '1'='
表中username
字段中的users
,并在查询字符串sqlQuery
中使用静态指定的查询只是将其合并,这是使用参数进行查询的方式:
SqlCommand command = new SqlCommand(sqlQuery,yourSqlConnection);
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@username";
parameter.Value = "xyz";
command.Parameters.Add(parameter);
评论
当参数化查询已解决问题时,为什么还要编写自己的验证?加上验证很难摆脱文本输入,并且参数化查询可以进行适当的“转义”(客户端实际上将数据直接传递给服务器)。
@dvhh:您能举个ESCAPING的例子吗?
无效!转义将是例如String.replace(“'”,“''”)。参数化的执行命令使用另一种编码形式,您几乎无需了解
为什么我们总是更喜欢在SQL语句中使用参数的可能重复项?