Php 什么时候使用真正的逃逸字符串合适?当数据以POST方式到达时,还是在编写查询之前?

Php 什么时候使用真正的逃逸字符串合适?当数据以POST方式到达时,还是在编写查询之前?,php,database,mysqli,escaping,code-injection,Php,Database,Mysqli,Escaping,Code Injection,我们知道,为了防止字符串值被转义,必须在组成SQL查询之前进行转义,特别是来自用户或其他外部源的值 这件事什么时候做?是否应在值进入程序时执行此操作,存储转义值以供以后使用?或者应该存储未转义的值,并在编写查询时转义它?哪种方法更安全?折衷是什么 1) 接收到值时转义的示例: $test = $mysqli->real_escape_string($_POST['test']); . . . $query=" UPDATE * from test_panel where test='

我们知道,为了防止字符串值被转义,必须在组成SQL查询之前进行转义,特别是来自用户或其他外部源的值

这件事什么时候做?是否应在值进入程序时执行此操作,存储转义值以供以后使用?或者应该存储未转义的值,并在编写查询时转义它?哪种方法更安全?折衷是什么

1) 接收到值时转义的示例:

$test = $mysqli->real_escape_string($_POST['test']);
. 
. 
. 
$query=" UPDATE * from test_panel where test='" . $test . "'";
2) 组成查询时转义的示例:

$test = $_POST['test'];
. 
. 
. 
$query=" UPDATE * from test_panel where test='" . $mysqli->real_escape_string('$test') . "'";

这些方法之间有区别吗?哪种方法更容易注射,什么是防止注射的最安全的方法?

无论是在查询之前还是在查询中转义输入都无关紧要

是的,一切都必须逃脱。你没有理由不想逃避自己的东西


如果您不想转义字符串,您会意识到;-)

你应该尽可能晚地逃离他们

您希望这样做的原因是,您的数据总是准确的。例如,如果在开头转义字符串,则strlen的
strlen
将与未转义的版本不同,这在某些情况下可能会导致混淆/错误



对于您的问题,真正的(imo)答案是忘记转义,使用

首先,您应该将连接作为mysqli real转义字符串中的第二个参数传递 其次,你还应该使用事先准备好的语句


在组成查询时实际使用之前,决不能转义值。无论您是使用准备好的语句/PDO,还是使用real_escape_字符串将查询组合为SQL格式的字符串,这都是正确的

过早清理/转义数据值并将其保存为该格式的做法会导致错误。如果变量包含数据值,如客户名称或帐号,则该变量应包含原始值un转义

只有当您实际形成查询时,才应该确保在将所有值放入该查询时对其进行了正确编码

将保存原始数据值的变量视为与保存查询的变量不同的变量类型。切勿将查询值直接指定给原始数据值,也不得将原始数据值组合起来进行查询。查询的组成是知道应该对原始数据值进行编码的触发器

通过将此作为一种实践,在编码发生的地方将变得清晰和一致,您将减少双重编码或编码失败的可能性

假设您试图做相反的事情:对所有值进行预编码。这实际上是不可能的,因为您有许多字符串值,并且并不是所有的字符串值都要在查询中使用。在某些地方,您可能会有一个变量,该变量既用作显示的输出,也用于查询。显示转义值将不正确。同样很难(或不可能)跟踪哪些变量用于查询,哪些变量用于其他非SQL用途


始终在所有字符串变量中存储原始(未转义)值,直到您实际编写查询为止。这种做法也与使用预处理语句一致,因为预处理语句会传递一个未转义的值

这是一个很有趣的问题,但答案并不那么容易

什么时候使用真正的逃逸字符串合适?当数据以POST方式到达时,还是在编写查询之前

两者都不是

让我解释一下

首先,让我们整理一下术语。这个问题提出的方式有很多错误

  • 让我们来谈谈格式化,而不是使用真正的_escape_字符串进行转义。因为转义的用途非常有限——它只是一种SQL文本格式规则的一部分。而其他类型需要不同的格式规则
  • 因此,数据“到达POST”时的格式设置是不成问题的——我们无法知道哪个字段将进入查询中的哪个位置,因此我们不知道应用哪些规则
  • 最后但并非最不重要的一点:nor POST或任何其他外部源都与查询格式无关。一旦必须将字符串文本放入查询中,就必须根据SQL语法规则对其进行格式化,无论其来源如何。数字等也一样
  • 因此,我们必须格式化数据的唯一适当时间是在组合查询之前

    然而,在应用程序代码中正确应用real_escape_string()是一种非常糟糕的做法

  • 如上所述,转义不足以格式化字符串。字符串格式包括转义和引用。因此,无论什么工具打算为SQL查询格式化字符串,它都应该同时执行两个任务,而不是一个任务。引用和转义。因为这两条规则如果一条没有另一条的话是完全无用的。因此,在一个设施中将它们结合在一起是非常必要的
  • 不要忘记不同数据类型的不同格式规则。数字必须显式转换为它的类型,而转义对它们没有好处
  • 手动逃逸是愚蠢的。重复的
    $mysqli->real\u escape\u字符串(“$test”)
    会使代码臃肿且难以阅读。为什么不让数据库驱动程序为您进行所有格式化?因此,您必须遵循最现代的技术—使用占位符来表示查询中的数据。在处理这样一个占位符时,驱动程序将自动格式化该占位符所在位置的数据。
    而且既安全又方便。
  • 有两种方法可以轻松地使用占位符(无需手动绑定,这对
    $db->prepare("SELECT * from test_panel where test=?");
    $db->execute(array($_POST['test']));
    
    function paraQuery()
    {
        global $mysqli;
    
        $args  = func_get_args();
        $query = array_shift($args);
        $query = str_replace("%s","'%s'",$query); 
    
        foreach ($args as $key => $val)
        {
            $args[$key] = $mysqli->real_escape_string($val);
        }
    
        $query  = vsprintf($query, $args);
        $result = $mysqli->query($query);
        if (!$result)
        {
            throw new Exception($mysqli->error()." [$query]");
        }
        return $result;
    }
    
    $query  = "SELECT * FROM table where a=%s AND b LIKE %s LIMIT %d";
    $result = paraQuery($query, $a, "%$b%", $limit);
    
    $result = paraQuery("SELECT * from test_panel where test=%s", $_POST['test']);