mysqli_real_escape_string - 100% 安全示例

mysqli_real_escape_string - example for 100% safety

我知道已经有很多关于这个话题的问题。而且我也知道要走的路是准备好的陈述。但是我仍然不完全理解以下是否或如何成为安全问题:

$mysqli = new mysqli("localhost", "root", "", "myDatabase");
$mysqli->set_charset("utf8");
$pw = mysqli_real_escape_string($mysqli,$_POST['pw']);
$username = mysqli_real_escape_string($mysqli,$_POST['username']);

$str = "SELECT * FROM users WHERE id='".$id."' AND username='".$username."'";
$result = $this -> mysqli -> query($qstr);

if($result->num_rows > 0){
    //user logged in
}

我尝试了很多来自注入欺骗的不同输入 sheet 但找不到任何通过查询的东西。例如。如果我用“;”输入任何内容然后 $result 变为假,因为据我所知,一个查询不能包含两个单独的语句。任何带有 ' 或 " 的输入都被 mysqli_real_escape_string。

你能给我解释一下,上面的代码是如何被利用的吗?如果你有 link 解释它,我也很乐意阅读它!

干杯

编辑:这个答案已经回答了:

SQL injection that gets around mysql_real_escape_string()

然而,这个问题是关于 mysql 的旧版本,而不是 mysqli。其次,得票最多的答案说明了以下可以绕过它的示例:

mysql_query('SET NAMES gbk');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

然而我并不完全理解这一点。第一行

mysql_query('SET NAMES gbk');

不能从外部设置,对吗?这只是一个例子,如果有人在他的程序中设置 'gbk'。所以如果我使用

$mysqli->set_charset("utf8");

也用过

id='".$id."' (single quotes around $id) 

那我就 100% 安全了,对吗?

您的孤立和简化示例在技术上是安全的。

但是,它还有两个问题:

  • 假设:问题的陈述是基于 mysqli_real_escape_string() 与任何安全问题相关的假设。这不过是一个严重的错觉。这是一个 字符串格式化函数 ,保护您免受 SQL 注入只是作为副作用。但是这样的保护既不是该功能的目标也不是目的。因此,绝不能将其用于此目的。
  • 您提出的代码的内在可分离性。保护由三个部分组成:
    • 设置正确的编码
    • 转义特殊字符
    • 将转义值用引号引起来

不仅是其中一些强制性措施 could be forgotten 的事实,而且问题的陈述再次强调了一个部分 - 逃避。只有逃避总是被强调,而其他两项措施几乎没有被提及。看看你的问题 - 你的意思是 code 但问的是 function。因此,对您提出的问题的任何字面回答都会给人一种致命的错误印象,即 mysqli_real_escape_string() 没问题。

In short, the statement of question helps to promote the most dangerous of PHP related delusions: that this function protects from SQL injection.

与这个复杂的三部分等式不同,准备好的语句构成了一个不可分割的度量。你不能忘记一个部分。你不能滥用它。尝试 mysqli_real_escape_string() 来保护一个标识符,它会悄无声息地被忽视,直到真正的注入发生。尝试为标识符准备好的语句 - 并得到一个错误。