64

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

  1. txtTagNumber作为查询参数传递

    SqlCommand cmd = new SqlCommand("INSERT INTO dbo.Cars " +"VALUES(@TagNbr);" , conn);
    cmd.Parameters.Add("@TagNbr", SqlDbType.Int);
    cmd.Parameters["@TagNbr"].Value = txtTagNumber.Text;
    
  2. 在构造查询之前转换txtTagNumber为整数

    int tagnumber = txtTagNumber.Text.ToInt16(); /* EDITED */
    INSERT into Cars values(tagnumber.Text); /* then is it the same? */
    

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

4

6 回答 6

55

参数化查询在运行 SQL 查询之前会正确替换参数。它完全消除了“脏”输入改变查询含义的可能性。也就是说,如果输入包含 SQL,则它不能成为执行内容的一部分,因为 SQL 从未注入到结果语句中。

于 2011-03-29T05:54:26.413 回答
30

想象一个动态 SQL 查询

sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND
Pass=' + password

所以一个简单的 sql 注入将只是将用户名放入 as' 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", 用户名) parameters.add("Pass", 密码)

其中用户名和密码是指向相关输入用户名和密码的变量

现在,您可能会想,这根本不会改变任何事情。当然,您仍然可以在用户名字段中输入“Nobody OR 1=1'--”之类的内容,从而有效地进行查询:

sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND
Pass=?'

这似乎是一个有效的论点。但是,你错了。

参数化查询的工作方式是将 sqlQuery 作为查询发送,并且数据库确切地知道该查询将做什么,然后才将用户名和密码仅作为值插入。这意味着它们不能影响查询,因为数据库已经知道查询会做什么。所以在这种情况下,它会寻找一个用户名"Nobody OR 1=1'--"和一个空白密码,这应该是假的。

资料来源:lavamunky.com;2011 年 11 月

于 2016-12-21T20:49:34.927 回答
23

当可能的参数中包含 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 where 1=1' 的行并且不运行剩余的脚本

于 2011-03-29T06:11:13.737 回答
3

参数化查询处理一切 - 为什么要麻烦?

使用参数化查询,除了一般注入之外,您还可以处理所有数据类型、数字(int 和 float)、字符串(带有嵌入式引号)、日期和时间(不调用 .ToString() 时没有格式问题或本地化问题使用不变的文化,您的客户会转移到具有意外日期格式的机器上)。

于 2011-03-29T06:01:25.927 回答
1

参数化查询允许客户端从查询文本中单独传递数据。在大多数没有文本的地方,您可以进行验证+转义。当然参数化对其他类型的注入没有帮助,但是由于参数是单独传递的,它们不能用作执行文本查询。

一个很好的类比是与大多数现代处理器和操作系统一起使用的“最近”执行位,以防止缓冲区溢出。它仍然允许缓冲区溢出,但阻止执行注入的数据。

于 2011-03-29T06:11:02.243 回答
1

为什么会有这样的感觉是完全可以理解的。

sqlQuery = "select * from users where username='+username+';"

对比

sqlQuery = "select * from users where username=@username;"

上述两个查询似乎都做同样的事情。但实际上并没有。

前者使用输入来进行查询,后者决定查询,但仅在执行查询期间替换输入。

更清楚地说,参数的值位于堆栈中存储变量内存的某个位置,并在需要时用于搜索。

因此,如果我们要' OR '1'='1在用户名中作为输入,前者将动态构造一个新的查询或查询作为 sql 查询字符串的一部分,sqlQuery然后执行。

在相同的输入上,后者将在查询字符串中使用静态指定的查询在表' OR '1'='username字段中进行搜索userssqlQuery

只是为了巩固它,这是您使用参数进行查询的方式:

SqlCommand command = new SqlCommand(sqlQuery,yourSqlConnection);

SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@username";
parameter.Value = "xyz";

command.Parameters.Add(parameter);
于 2016-03-17T09:40:34.240 回答