其他答案已经涵盖了您需要知道的内容。但也许有助于澄清更多信息:
有两件事情你需要做的:
1.验证表单数据。
正如乔纳森·霍布斯(Jonathan Hobbs)的答案非常清楚地表明,为表单输入选择html元素不会为您做任何可靠的过滤。
验证通常以不会更改数据的方式进行,但是会再次显示该表单,其字段标记为“请更正此”。
大多数框架和CMS都有表单构建器来帮助您完成此任务。不仅如此,它们还有助于抵御CSRF(或“ XSRF”),这是另一种攻击形式。
2.在SQL语句中清理/转义变量。
..或让准备好的语句为您完成工作。
如果使用任何用户提供或不提供的变量构建(My)SQL语句,则需要转义并引用这些变量。
通常,您插入MySQL语句中的任何此类变量应为字符串,或者PHP可以可靠地转换为MySQL可以消化的字符串。如数字。
对于字符串,然后需要选择几种方法中的一种来对字符串进行转义,也就是说,替换在MySQL中可能产生副作用的任何字符。
- 在老式的MySQL + PHP中,mysql_real_escape_string()可以完成这项工作。问题在于它太容易忘记了,因此您绝对应该使用准备好的语句或查询构建器。
- 在MySQLi中,您可以使用准备好的语句。
- 大多数框架和CMS提供查询构建器,以帮助您完成此任务。
如果要处理数字,则可以省略转义和引号(这就是准备好的语句允许指定类型的原因)。
重要的是要指出,您对SQL语句而不是数据库本身对变量进行了转义。数据库将存储原始字符串,但是该语句需要转义的版本。
如果您忽略其中之一,该怎么办?
如果您不使用表单验证,但是确实对SQL输入进行了清理,则可能会看到各种不良情况,但是您不会看到SQL注入!(*)
首先,它可以使您的应用程序进入您未计划的状态。例如,如果您要计算所有用户的平均年龄,但是一个用户输入了“ aljkdfaqer”作为年龄,则计算将失败。
其次,您可能需要考虑各种其他注入式攻击:例如,用户输入可能包含javascript或其他内容。
数据库仍然存在问题:例如,如果字段(数据库表列)限制为255个字符,并且字符串比该字符串长。或者,如果该字段仅接受数字,而您尝试保存一个非数字字符串。但这不是“注入”,而只是“崩溃应用程序”。
但是,即使您有一个自由文本字段,该字段允许所有输入都完全不进行验证,但如果在处理数据库语句时正确地将其转义,则仍然可以将其保存到数据库中。当您想在某个地方使用此字符串时,问题就来了。
(*),否则这将是真正的异国情调。
如果您没有为SQL语句转义变量,但是您确实验证了表单输入,那么您仍然可以看到不良情况的发生。
首先,您冒着将数据保存到数据库中并再次加载时的风险,即不再是相同的数据,即“翻译丢失”。
其次,它可能导致无效的SQL语句,从而使您的应用程序崩溃。例如,如果任何变量包含引号或双引号字符,则取决于您使用哪种引号类型,您将获得无效的MySQL语句。
第三,它仍然可能导致SQL注入。
如果您已经过滤/验证了来自表单的用户输入,则如果将您的输入简化为选项的硬编码列表,或者将其限制为数字,则可能不太可能进行故意的 SQl注入。但是,如果您没有正确地转义SQL语句中的变量,则任何自由文本输入都可以用于SQL注入。
即使根本没有任何形式的输入,您仍然可以从各种来源获得字符串:从文件系统读取,从Internet抓取等。没有人可以保证这些字符串是安全的。
<select>
输入中提交他们想要的任何值。实际上,即使是稍微技术的用户也可以使用浏览器控制台添加其他选项。如果您保留可用值的数组白名单并与输入进行比较,则可以减轻这种情况(并且应该这样做,因为它可以防止出现不必要的值)