php - PHP Prepared Statement调用的存储过程中的Prepared Statement
问题描述
我只是想知道从安全的角度来看这是否有任何优点。假设我有一个 PHP 脚本需要从数据库中获取一些东西。用 PHP 写出来并以这种方式使用准备好的语句是否更安全,将所有内容封装在 MySQL 存储过程中是否更安全,或者我实际上可以从使用 PHP 准备好的语句调用存储的 MySQL 中获得任何安全好处有一个准备好的语句的过程。或者,只要我在某处使用准备好的语句,这真的不重要吗?类似于以下内容,但可能更复杂一些:
PHP:
require 'path/to/login_utils.php';
try {
$username = sanitize_validate_username($_POST['username']); // custom cleaning function from login_utils
$pdo = connect_to_database(); // custom connection function from login_utils
$select = "SELECT `password`
FROM `tbl_login`
WHERE `username`=:username;";
$prepared = $pdo->prepare($select);
$prepared->bindValue(":username", $username);
$prepared->execute();
$result = $prepared->fetchAll(PDO::FETCH_ASSOC);
$prepared->closeCursor();
if (isset($result) && count($result) > 0) {
$password = $result['password'];
}
} catch (PDOException $e) {
die $e->getCode() . ': ' . $e->getMessage();
} finally {
if (isset($pdo)) {
unset($pdo);
}
}
$userpass = $_POST['userpass'];
if (!isset($password) || !password_verify($userpass, $password)) {
die 'Invalid username and password combo';
}
start_authenticated_session(); // custom session starting function from login_utils
echo 'You have been logged in';
exit;
但是,如果我不是在 PHP 中动态地进行 SELECT 操作,而是将它放在具有类似这样的存储过程的后面呢?
MySQL:
DELIMITER $$
CREATE PROCEDURE usp_GetUserPassword(IN @username VARCHAR(255))
this_proc: BEGIN
IF @username IS NULL
THEN LEAVE this_proc;
END IF;
DECLARE @password VARCHAR(64);
PREPARE get_password
FROM 'SET @password = (
SELECT `password`
FROM `tbl_login`
WHERE `username`=?
);';
EXECUTE get_password USING @username;
DEALLOCATE PREPARE get_password;
SELECT @password;
END$$
DELIMITER ;
然后在我的 PHP 脚本中调用它,将第一个 SELECT 替换为:
$select = "CALL usp_GetUserPassword(:username);";
或者类似的东西,我继续$select
在 PHP 中准备和执行,即使存储过程里面有一个准备好的语句。这会增加任何额外的安全性吗?
解决方案
坦率地说,存储过程没有提供您无法通过在 SQL 中使用直接从应用程序代码准备和执行的查询参数轻松有效地获得的安全性。
并且存储过程在 MySQL 中更难开发。没有调试器,没有包支持,没有标准库,文档很薄而且难以阅读,没有持久编译器,等等。
在Microsoft/Oracle/IBM,存储过程比较成熟,传统的做法是为一个项目开发大包的过程。但是在 MySQL 中,我几乎从不使用存储过程。
对于 SQL 注入预防,请使用查询参数。它更容易也同样有效。
推荐阅读
- post - 从邮递员 POST 上传文件
- java - 检查 dateTime 的格式是否匹配自定义格式(“dd/MM/yyyy HH:mm:ss”) - Java
- firebase - 文档快照不退出
- python - 如果满足条件,作业将自行删除
- c++ - 为什么在 C++20 中允许这个值向下转换(static_cast 到对象类型)?
- mysql - 如果共享相同的时间戳,则多次选择一列作为单独的列
- dataframe - Spark Cassandra CassandraSourceRelation directJoinSetting 异常错误
- html - 如何在 css 中平铺 div 背景以在每个屏幕上填充我的 html?
- c++ - `unordered_map`中的高效节点提取()+插入()
- java - Java Android 自定义 ArrayAdapter 条件渲染