参数化查询如何帮助防范SQL注入?
在查询1和2中,文本框中的文本都被插入到数据库中。 这里的参数化查询有什么意义?
1。> ————-
SqlCommand cmd = new SqlCommand("INSERT INTO dbo.Cars " +"VALUES(@TagNbr);" , conn); cmd.Parameters.Add("@TagNbr", SqlDbType.Int); cmd.Parameters["@TagNbr"].Value = txtTagNumber.Text;
2。> ————–
int tagnumber = txtTagNumber.Text.ToInt16(); /* EDITED */ INSERT into Cars values(tagnumber.Text); /* then is it the same? */
此外,在这里我会使用正则expression式validation来停止插入非法字符。
参数化查询在运行SQL查询之前进行正确的参数replace。 它完全消除了“脏”input改变查询含义的可能性。 也就是说,如果input包含SQL,则不能成为执行的一部分,因为SQL从未注入到结果语句中。
当一个可能的参数在其中有sql并且string没有按照它应该被处理时,sql注入发生
例如:
var sqlquerywithoutcommand = "select * from mytable where rowname = '" + condition+''";
并且该条件是请求中来自用户的string。 如果条件是恶意的,例如:
var sqlquerywithoutcommand = "select * from mytable where rowname = '" + "a' ;drop table mytable where '1=1"+"'";
您最终可能会运行恶意脚本。
但使用参数input将清除任何可能转义string字符…
你可以确保不pipe进来什么都不能运行注入脚本。
使用带有参数的命令对象,实际执行的sql看起来像这样
select * from mytable where rowname = 'a'';drop table mytable where 1=1'''
在本质上它将寻找一行rowname = a'; drop table mytable where 1 = 1',而不运行剩余的脚本
想象一下dynamicSQL查询
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
这就是说select所有的用户名是空白的('')或1 = 1,这是一个布尔值,等于true。 然后它使用 – 注释掉其余的查询。 因此,这只会打印出所有的客户表,或者做任何你想做的事情,如果login,它将以第一个用户的权限login,这通常是pipe理员。
现在参数化的查询以不同的方式执行,代码如下:
sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?'
parameters.add(“用户”,用户名)parameters.add(“Pass”,密码)
其中用户名和密码是指向相关的input用户名和密码的variables
现在,在这一点上,你可能会想,这根本没有任何改变。 当然,你仍然可以只是把用户名字段像没有人或1 = 1' – 有效地进行查询:
sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND Pass=?'
这似乎是一个有效的论点。 但是,你会错的。
参数化查询的工作方式是将sqlQuery作为查询发送,数据库确切知道该查询将执行的操作,只有这样才能将用户名和密码作为值插入。 这意味着它们不会影响查询,因为数据库已经知道查询将执行什么操作。 所以在这种情况下,它会查找一个用户名
"Nobody OR 1=1'--"
和一个空的密码,这应该是错误的。
取自
参数化的查询处理一切 – 为什么要麻烦?
使用参数化查询,除了通用注入之外,还可以处理所有的数据types,数字(int和float),string(带有embedded式引号),date和时间(没有格式化问题或当没有调用.ToString与不变的文化和你的客户移动到一台机器与意想不到的date格式)。
参数化查询允许客户从查询文本分别传递数据。 在大多数免费的文本你会做validation+转义。 当然参数化对于其他types的注入没有帮助,但是由于参数是分开传递的,所以它们不能用作执行文本查询。
一个很好的比喻是大多数现代处理器和操作系统使用“最近”的执行位来防止缓冲区溢出。 它仍然允许缓冲区溢出,但是阻止注入数据的执行。
为什么会这样呢,这是可以理解的。
sqlQuery = "select * from users where username='+username+';"
VS
sqlQuery = "select * from users where username=@username;"
上述查询似乎都做了同样的事情,但他们实际上没有。
前者使用input来进行查询,后者在查询上做出决定,但只是在执行查询期间replaceinput。
更清楚的是,参数的值位于variables存储器所在栈的某处,并在需要时用于search。
所以如果我们要给' OR '1'='1
sqlQuery
' OR '1'='1
作为用户名的input,前者会dynamic地构造一个新的查询或查询作为sql查询stringsqlQuery
一部分,然后执行。
而在相同的input时,后者将在查询stringsqlQuery
中使用静态指定的查询在users
表的username
字段中search' OR '1'='
sqlQuery
' OR '1'='
只是为了巩固它,这是你如何使用参数进行查询:
SqlCommand command = new SqlCommand(sqlQuery,yourSqlConnection); SqlParameter parameter = new SqlParameter(); parameter.ParameterName = "@username"; parameter.Value = "xyz"; command.Parameters.Add(parameter);