我们知道,在编写SQL查询之前必须转义防止SQL injection problems字符串值 - 特别是来自用户或其他外部源的字符串。
何时应该逃脱?是否应该在值进入程序时完成,存储转义值以供以后使用?或者应该存储未转义的值,并在查询编写时将其转义?哪种方法更安全?什么是权衡?
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') . "'";
这些方法之间有区别吗?哪种方法更容易注射,哪种方法最安全?
答案 0 :(得分:1)
这是一个非常有趣的问题,但答案并不那么容易。
使用real_escape_string的正确时间是什么?当数据到达POST时,或者在编写查询之前?
<强> NEITHER 强>
让我解释一下。
首先,让我们理清术语。提出问题的方式有很多错误。
因此,我们必须格式化我们的数据的唯一合适时间就在查询撰写之前。
然而,在应用程序代码中应用real_escape_string()是一种非常糟糕的做法。
$mysqli->real_escape_string('$test')
使您的代码变得臃肿且难以阅读。为什么不让数据库驱动程序为您执行所有格式化?因此,您必须遵循最先进的技术 - 使用占位符来表示查询中的数据。处理这样的占位符时,驱动程序会自动格式化其所在位置的数据
它既安全又方便。 有两种方法可以轻松使用占位符(没有手动绑定,在可读性方面不比手动转义好):
所以,代码将是
$db->prepare("SELECT * from test_panel where test=?");
$db->execute(array($_POST['test']));
和PDO将在内部完成所有格式化
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']);
看起来 - 它变得简短,健全且安全。
答案 1 :(得分:0)
你应该尽可能地逃避它们。
您希望这样做的原因是您的数据始终是准确的。例如,如果您在开始时直接转义字符串,strlen
将不会相同(与非转义版本相同),这可能会在某些情况下导致混淆/错误。
真正的(imo)回答你的问题就是忘记逃避并使用prepared statements
'
答案 2 :(得分:-1)
在查询之前或查询中转义输入无关紧要。
是的,一切都必须逃脱。没有理由,为什么你不想逃避自己的事情。
如果你不想逃避字符串,你会意识到它; - )
答案 3 :(得分:-1)
在编写查询的实际使用之前,永远不应对值进行转义。无论您使用预准备语句/ PDO还是使用real_escape_string将查询组成SQL格式的字符串,都是如此。
过早清理/转义数据值并以该形式保存数据的做法会导致错误。如果变量包含数据值(如客户名称或帐号),则该变量应包含未转义的原始值。
只有当您实际形成查询时,才能确保所有值都正确编码,因为它们被放入该查询。
将包含原始数据值的变量视为包含查询的变量的不同类型的变量。切勿直接将查询值分配给原始数据值,也不要将原始数据值组合起来进行查询。编写查询是触发器,知道您应该对原始数据值进行编码。
通过实践这一点,在编码发生的情况下,它将是清晰且一致的,您将减少双重编码或编码失败的可能性。
想象一下,您尝试执行相反的操作:预编码所有值。这实际上是不可能的,因为您有许多字符串值,并且并非所有字符串值都用于查询。在某个地方,您可能有一个变量既可用作显示输出,也可用于查询。显示转义值将不正确。同样很难(或不可能)跟踪哪些变量用于查询,哪些变量用于其他非SQL用途。
始终在所有字符串变量中存储原始(未转义)值,直到您实际撰写查询为止。这种做法也与使用预准备语句一致,因为准备好的语句会传递一个未转义的值。
答案 4 :(得分:-2)
首先,您应该将连接作为mysqli real escape string中的第二个参数传递 其次,你还应该使用准备好的陈述