在查询1和2中,来自文本框的文本都插入到数据库中。参数化查询在这里的意义是什么?



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? */



此外,这里我将使用正则表达式验证来停止插入非法字符。

评论

当参数化查询已解决问题时,为什么还要编写自己的验证?

加上验证很难摆脱文本输入,并且参数化查询可以进行适当的“转义”(客户端实际上将数据直接传递给服务器)。

@dvhh:您能举个ESCAPING的例子吗?

无效!转义将是例如String.replace(“'”,“''”)。参数化的执行命令使用另一种编码形式,您几乎无需了解

为什么我们总是更喜欢在SQL语句中使用参数的可能重复项?

#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);