在查询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? */
此外,在这里我将使用正则表达式验证来停止插入非法字符。
参数化查询在运行SQL查询之前正确替换参数。它完全消除了“脏”输入改变查询含义的可能性。也就是说,如果输入包含SQL,则它不能成为执行内容的一部分,因为SQL从未注入到生成的语句中。
当一个可能的参数在其中包含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'''
在essense中,它将使用rowname = a'; drop table mytable,其中1 = 1'并且不运行剩余的脚本
想象一下动态SQL查询
sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND Pass=' + password
所以一个简单的SQL注入只是将用户名放在
' 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)parameters.add(“Pass”,password)
其中用户名和密码是指向相关输入的用户名和密码的变量
现在,在这一点上,你可能会想,这根本不会改变任何东西。当然你仍然可以在用户名字段中输入类似Nobody OR 1 = 1'的内容,从而有效地进行查询:
sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND Pass=?'
这似乎是一个有效的论点。但是,你错了。
参数化查询的工作方式是,sqlQuery作为查询发送,数据库确切知道此查询将执行的操作,然后才会将用户名和密码仅作为值插入。这意味着它们不能影响查询,因为数据库已经知道查询将执行什么操作。所以在这种情况下,它会寻找
"Nobody OR 1=1'--"
的用户名和一个空密码,这应该是假的。
参数化查询处理所有事情 - 为什么要麻烦?
使用参数化查询,除了通用注入之外,还可以获得所有处理的数据类型,数字(int和float),字符串(带嵌入引号),日期和时间(没有格式问题或本地化问题,而不调用.ToString()随着不变的文化和您的客户移动到具有和意外日期格式的机器)。
参数化查询允许客户端从查询文本中单独传递数据。在大多数免费文本的地方你会做验证+逃避。当然,参数化对其他类型的注入没有帮助,但是当参数单独传递时,它们不用作执行文本查询。
一个很好的类比是与大多数现代处理器和操作系统一起使用的“最近”执行位,以防止缓冲区溢出。它仍允许缓冲区溢出但阻止执行注入的数据。
人们为什么会这样感觉是完全可以理解的。
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);