当文章谈论参数化查询阻止 SQL 攻击时,他们并没有真正解释原因,通常是“确实如此,所以不要问为什么”——可能是因为他们不了解自己。糟糕的教育者的一个明显标志是不能承认自己不知道某些事情。但我离题了。
当我说我发现困惑很简单是完全可以理解的。想象一下动态 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'--”和空白密码,这应该会出现错误。
但这不是一个完整的解决方案,仍然需要完成输入验证,因为这不会影响其他问题,例如 XSS 攻击,因为您仍然可以将 javascript 放入数据库中。然后,如果将其读出到页面上,它将根据任何输出验证将其显示为普通 JavaScript。因此,最好的做法仍然是使用输入验证,但使用参数化查询或存储过程来阻止任何 SQL 攻击。