php - 将常规 mysql 转换为准备好的语句

标签 php mysql sql-injection

我是数据库的新手,我编写了很多使用 MySQL 访问数据库的 PHP 代码。

我没有考虑到 SQL 注入(inject)攻击,所以我不得不重写所有 PHP 代码以使用 mysql 准备好的语句。

在观看了有关如何使用准备好的 SQL 语句的视频后,要执行一条 SQL 命令需要一大堆“准备好的”语句。我现有的代码到处都有很多不同的 SQL 语句,更改所有代码以打包和解包每个“准备好的”语句命令所需的所有准备工作将是一场噩梦。

是否可以使用某种包装器来防止将一行常规 SQL 转换为 6 或 7 行准备好的语句?

例如用来做这行SQL语句

SELECT * from users where userid=10

需要更多行准备好的 SQL 语句,特别是如果还有很多其他 SQL 语句,现在变得非常复杂。

是否有某种我可以调用的单行包装器,它接受模板 SQL 字符串和参数,它还执行命令并在不同类型的 MYSQL 语句的仅一行包装器中返回结果很棒,代码看起来不会那么困惑,也不会容易出错。

例如

 $users=WrapAndExecute($db,"SELECT * from users where userid=?","s",$userid);

 $data=WrapAndExecute($db,"UPDATE table SET username=?,city=?","ss",$name,$city);

 $result=WrapAndExecute($db,"DELETE from table where id=?","s",$userid);

 $result=WrapAndExecute($db,"INSERT into ? (name,address) VALUES(?,?)","ss","users",$name,$address);

上面的每一行都会创建一个准备好的语句模板,进行绑定(bind),执行它并返回常规 MYSQL 语句的结果。这将对现有代码产生最小的影响。

任何人都知道如何做到这一点,或者如果已经存在一些简单的 php 库或类来做到这一点,我可以导入并开始使用它吗?

谢谢

最佳答案

如果其中没有 PHP 变量,则无需将查询更改为准备好的语句。如果它只有常量表达式,它就不会受到 SQL 注入(inject)攻击。

$sql = "SELECT * from users where userid=10"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();

您无需更改包含 PHP 变量的查询,只要该变量的值是代码中指定的常量即可。如果它不从任何外部来源获取它的值(value),它就是安全的。

$uid = 10;
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();

您不需要更改包含 PHP 变量的查询,只要您可以过滤该值以保证它不会冒 SQL 注入(inject)的风险。一种快速简便的方法是将其转换为一个整数(如果它应该是一个整数)。

$uid = (int) $_GET['uid'];
$sql = "SELECT * from users where userid=$uid"; // Safe!
$stmt = $pdo->query($sql);
$data = $stmt->fetchAll();

这会导致您使用“不受信任”的值,这些值可能源自用户输入、读取文件,甚至从数据库读取。在那些情况下,参数是保护您自己的最可靠方法。这很简单:

$sql = "SELECT * from users where userid=?"; // Safe!

// two lines instead of the one line query()
$stmt = $pdo->prepare($sql);
$stmt->execute([$_GET['uid']]);

$data = $stmt->fetchAll();

在某些情况下,您需要比通常使用的额外一行代码

所以停止提示吧! ;-)


关于在 mysqli 中执行准备好的语句的评论。

它们绑定(bind)变量的方式比 PDO 更难使用。我不喜欢 http://php.net/manual/en/mysqli.prepare.php 中给出的示例

这是使用 mysqli 的更简单的方法:

$sql = "SELECT * from users where userid=?"; // Safe!

$stmt = $mysqli->prepare($sql);
$stmt->bind_param('i', $_GET['uid']);
$stmt->execute();
$result = $stmt->get_result();

$data = $result->fetch_all();

我不喜欢他们在示例中使用 bind_result() 所做的事情,这令人困惑且没有必要。只需使用 get_result()。因此,使用 mysqli,您需要比使用 PDO 多两行代码。

我已经为 mysqli 编写了查询包装器,它模拟了 PDO 的 execute() 函数的便利性。将数组映射到 bind_param() 的可变参数样式是一个 PITA。

请参阅我对 https://stackoverflow.com/a/15933696/20860 的回答中的解决方案或 https://stackoverflow.com/a/7383439/20860

关于php - 将常规 mysql 转换为准备好的语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43374839/

相关文章:

php - 警告 : mysql_num_rows() expects parameter 1 to be resource, 中给出的 bool 值

php - ssl 证书问题 : unable to get local issuer certificate xampp

php - MySQL 错误,SQL 新手

mysql - 使用外键连接多个 MySQL 表

php - md5是否可以阻止SQL注入(inject)

php - cakephp中特定字段的数据转义删除

php - SQL 条件 : (A=B AND C LIKE %D%) OR (A LIKE %B% AND C=D)

mysql - 如何进行 if 和 else mysql 查询

php - 如何验证或限制用户的直接 SQL 输入?

php - 如何防止 PHP 中的 SQL 注入(inject)?