目前我有一些数据库包装器函数,如下所示:
function db_escape($str) {
return mysql_real_escape_string($str);
}
function db_query($sql) {
global $LINKID;
return mysql_query ($sql, $LINKID);
}
function db_fetch_array($result) {
return mysql_fetch_array ($result, MYSQL_ASSOC);
}
在我的代码中,我可以执行以下操作:
$result = db_query('SELECT userid, first_name, last_name FROM user
WHERE email = "' . db_escape($email) . '"');
if ($result) {
$user = db_fetch_array($result);
}
这背后的一个想法是,当我从 mysql 切换到 mysqli 时,只需几分钟即可更新我的包装器函数,而且我不必在数百个不同的项目中替换数百个mysql_real_escape_string()
、mysql_query()
和mysql_fetch_array()
实例。
唯一的问题是,上述内容可以很容易地转换为标准的过程 mysqli 函数,但不能转换为预处理语句。
这重要吗? 似乎每个教程都说准备好的语句对于安全性和性能很重要,但是目前:
- 我的所有项目都没有性能问题。
- 我非常喜欢将用户输入转换为预期类型(字符串、整数、浮点数等),并且还要手动转义查询中任何地方使用的任何用户输入。
考虑到这一点,对于过去或未来的项目,是否真的有必要切换到准备好的陈述?
我认为你应该考虑长期利益。例如,如果将来您不再是该项目的开发人员,则使用非准备语句的习惯将传递给下一个开发人员,如下所示:
我非常喜欢将用户输入转换为预期类型(字符串、整数、浮点数等),并且还要手动转义查询中任何地方使用的任何用户输入。
可能不再是真的了。即使你说你非常小心,在某些时候你会犯错误或忘记(是的,人们做到了!这就是事情破裂的原因),那么这将是一个问题。
以以下案例为例。你认为安全吗?
$id = $_POST['id'];
$result = db_query('SELECT userid, first_name, last_name FROM user
WHERE userid = ' . db_escape($id) );
虽然看到另一位斯马特先生提出他的永久手机,我感到有些恼火,但我不能说他的想法在某种程度上完全不合理。但是,不幸的是,它们都是基于错误的假设。
哪些是
- SQL 格式规则仅限于转义和强制转换
- 需要针对 SQL 注入提供的任何保护
- 这种保护应应用于用户输入
- 每个PHP应用程序都很小且可观察
- 就像另一个答案中提到的,只有一个开发人员将所有代码都记在脑海中,曾经在项目上工作。
但同样,所有这些假设都是错误的。
一旦你重新思考它们,你就会得出结论,只有参数化查询才能给你一个保险账单。请注意,我说的是使用参数的一般思想,而不是mysqli中使用的特定实现。即使使用旧的mysql ext也可以实现这个想法。
要考虑的另一件事是代码的美观和大小。看看你现在拥有什么
$result = db_query('SELECT userid, first_name, last_name FROM user
WHERE email = "' . db_escape($email) . '"');
if ($result) {
$user = db_fetch_array($result);
}
以及可以使用参数做什么
$sql = 'SELECT userid, first_name, last_name FROM user WHERE email = ?';
$user = db_fetch_array($sql, $email);