我知道这是一个非常受欢迎的问题,而且经过多个小时的研究,我仍然对确定的答案有点不确定。我不是PHP的专家,现在已经自学了一段时间了。我最近刚刚掌握了MYSQLi准备好的陈述(已经习惯了以前的做法)。
我的主要问题是在使用预准备语句时,试图找到关于使用真实转义字符串(或任何其他安全性)的要求的确定答案。
我已准备好通过以下问题:
Prepared Statements, escape variables
IF I use mysqli prepared statements do i need to escape
Do PHP PDO prepared statments need to be escaped?
但是在使用预准备语句时似乎存在支持和反对转义数据的论据。还有很多关于PDO的提及对我来说非常混乱,因为我不是PHP的天才。
我期待这个伟大的社区帮助我完全理解并给我一个答案(以某种方式,我希望能理解),以便我进步。
为此,我有以下例子,并询问是否有人可以用非专业术语解释哪些不使用,哪些不使用,更重要的是,为什么?
我目前正在整个代码中使用它:
$qry = $conn->prepare('INSERT INTO status (id, name, message, date) VALUES (?, ?, ?, NOW())');
$qry->bind_param('iss', $_POST['id'], $_POST['name'], $_POST['message']);
$qry->execute();
$qry->close();
但是,我对上述示例问题的理解有限,告诉我使用以下代码是安全/可行的:
vector<Parent>
那么,哪种方法最好?抱歉这个冗长的问题。研究过它并试图理解它我只想确定原因。
感谢大家的时间和支持,我非常感谢您提供的任何帮助。
答案 0 :(得分:3)
注意:这个答案使用了一个过于简单化的模型,说明了逃避和准备语句实际上做了什么。
SQL是一种语言。其中的一些字符具有特殊含义。例如,'
分隔字符串的开头和结尾。
当您转义数据时,您将\
放在具有特殊含义的字符前面。这导致它们意味着(例如)“撇号”而不是“字符串的结尾”。
所以:
$id = $conn->real_escape_string($_POST['id']);
现在,如果ID中有'
,则不会破坏SQL。
当您使用绑定变量时,它将自动为您转义。
$qry->bind_param('iss', $id, $name, $message);
现在,如果ID中有'
,则不会破坏SQL。
......除了你已经这样做了。
现在,您已将'
变为\'
,然后转入\\\'
,因为'
已转义,然后再次与{{1}一起转义从第一次逃跑开始。
所以现在第一个\
被视为数据(而不是特殊的SQL字符)并被插入到数据库中。
使用准备好的陈述。使用仅预备语句。
(例外情况是当您使用变量而不能执行准备好的语句时,例如动态表名称,这应该不常见)。
答案 1 :(得分:1)
如果您使用预准备语句,则绝对不需要使用real_escape_string()
或任何其他类似函数来转义参数。事实上,如果你逃避它,你最终可能会获得双重转义值。
你的第二个例子完全有效。
答案 2 :(得分:1)
答案在PHP docs:
中关于准备陈述的文章中说明转义和SQL注入
绑定变量与查询分开发送到服务器,因此不会干扰它。在解析语句模板之后,服务器直接在执行点使用这些值。绑定参数不需要转义,因为它们永远不会直接替换为查询字符串。 [...]
这种分离有时被认为是防止SQL注入的唯一安全功能,但如果所有值都正确格式化,则可以使用非预处理语句实现相同程度的安全性。应该注意的是,正确的格式与转义不同,涉及的逻辑比简单的转义更多。因此,准备好的语句对于这个数据库安全元素来说只是一种更方便,更不容易出错的方法。
(强调我的)。
请注意,在绑定参数之前,数据库引擎会编译预准备语句。它确实是能够使用参数执行此查询的数据库引擎。在任何时候都没有创建一个SQL字符串,它将准备好的SQL语句的字符串与参数的字符串版本连接起来。
将SQL视为我们人类的语言。另一方面,数据库引擎在它可以执行任何操作之前不需要在纯SQL字符串中包含所有内容。相反,它需要先解析SQL才能执行任何操作。所以它可以处理两条信息(准备好的声明,参数) 无需先构建完整的SQL字符串即可生成所需的输出。并且因为它不构建该字符串,所以它也不需要转义任何东西。不会为SQL构造解析参数(这将是SQL注入风险)。它们被用作值,仅此而已。