最近,我切换到PDO,想问一下是否和我一样安全?
((我以前使用php提供的许多过滤方法过滤数据)
QUERY db:
include 'path_to_config_file_with_login_creds_for_db.php';
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
PDO::ATTR_PERSISTENT => false,
);
try {
$pdo = new PDO('mysql:host=' . $database_host . ';dbname=' . $database_name . ';charset=utf8mb4', $database_user, $database_pass, $options);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $exception) {
die("some error message");
}
try {
$statement = $pdo->prepare($sql);
$statement->execute($bindings);
$statement->closeCursor();
return $output;
} catch (PDOException $stmEx) {
die("again some error message");
}
更新数据库:
include 'again_path_to_config_file_where_creds_to_db.php';
$options = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT,
PDO::ATTR_PERSISTENT => false,
);
try {
$pdo = new PDO('mysql:host=' . $database_host . ';dbname=' . $database_name . ';charset=utf8mb4', $database_user, $database_pass, $options);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $exception) {
die("...");
}
try {
$statement = $pdo->prepare($sql);
$statement->execute($bindings);
$statement->closeCursor();
} catch (PDOException $stmEx) {
die("...");
}
这种方法是否安全?
一切正常,但我也想知道它的安全性
关于SQL注入,只要您将所有输入参数化并将所有动态SQL部分列入白名单,您就应该是安全的。
但是,您的代码还有另一个严重的问题。您正在沉默错误。 PDO::ATTR_ERRMODE
应设置为PDO::ERRMODE_EXCEPTION
。但是,这将使您的代码处于更糟糕的状态,因为到处都是die
。除非您有充分的理由这样做,否则不要捕获异常。阅读本文https://phpdelusions.net/pdo#errors
向用户静音或显示错误会为利用打开新的载体。这就是为什么最好的行动方针是让他们独自一人。在生产系统中,应将配置设置为从不显示错误。它们将被安全地登录到服务器上。
从安全角度来看,只要$ sql中的查询正确使用了参数绑定,它就应该是安全的。如果$ sql变量是这样构建的,那么您的代码将无济于事。
//DO NOT TRY THIS AT HOME
$sql = "SELECT * FROM `users` WHERE user='" . $_POST['user'] . "'";
但是我可以在您的代码中看到其他几个问题。
1]您的try ... catch
块无用。当您使用PDO::ERRMODE_SILENT
时,PDO不会引发任何异常。遇到错误时,将仅设置$pdo->errorCode
或$statement->errorCode
属性。
2)您打开的连接过多。我假设您已经共享了打算在某些函数中共享的代码,例如queryDb($sql, $params);
,这意味着每次调用该函数时,都将创建PDO
的新实例并打开新的连接。您可能想将创建PDO实例的部分移到db-config文件中,然后每次使用$pdo->prepare()
创建新语句时都使用该单个实例。
3)使用die
。在示例中查询出错时,通常使用die
或exit
。但是在实际应用中,这意味着用户将看到丑陋的空白页面,上面只有一句话,说出了问题。最好抛出一个异常,该异常将在您的应用程序中得到更高的处理。即使请求的操作失败,也可以使应用程序显示带有菜单和其他内容的页面布局。
4)您没有在代码的第一个“查询数据库”部分中将值设置为$ output变量。尽管我不确定在复制时是否只是将其遗漏,或者在实际代码中是否有这样的内容。