Php 具有动态预处理语句的安全、可扩展数据库

Php 具有动态预处理语句的安全、可扩展数据库,php,mysql,database,pdo,sql-injection,Php,Mysql,Database,Pdo,Sql Injection,问题: 我的任务是创建一个数据库来保存各种产品的信息,并创建RESTfulAPI来服务和管理这些信息。但是客户机并不确切知道他们需要这些产品的所有信息,因此数据库可能会在以后添加新的列和表以适应新的产品属性。我的问题是如何生成一个数据库,该数据库将随时接受这些更改,并构建查询,以便能够基于产品属性安全地获取产品,而这些产品属性目前还不存在,只需很少或根本不需要修改 建议的解决方案: 我有一个具有以下结构的测试数据库设置 +------------------+ | item

问题: 我的任务是创建一个数据库来保存各种产品的信息,并创建RESTfulAPI来服务和管理这些信息。但是客户机并不确切知道他们需要这些产品的所有信息,因此数据库可能会在以后添加新的列和表以适应新的产品属性。我的问题是如何生成一个数据库,该数据库将随时接受这些更改,并构建查询,以便能够基于产品属性安全地获取产品,而这些产品属性目前还不存在,只需很少或根本不需要修改

建议的解决方案: 我有一个具有以下结构的测试数据库设置

+------------------+
|      item        |
+----+------+------+
| id | name | cost |
+----+------+------+
|  0 | test |   50 |
+----+------+------+

+--------------+
|    color     |
+----+---------+
| id |   val   |
+----+---------+
|  0 |  blue   |
|  1 | purple  |
+----+---------+

+--------------------+
|      item_color    |
+---------+----------+
| item_id | color_id |
+---------+----------+
|       0 |        0 |
|       0 |        1 |
+---------+----------+
“item”表可能会在以后添加列,也可能会添加更多的连接表

需要检索产品的请求 使用php,我动态地构造准备好的语句来检索相关的产品,希望不会打开sql注入的大门。首先,我使用以下函数确定哪些属性包含在“item”表中,哪些属性包含在单独的表中:

function column_exists($column, $pdo) {
    $statement = $pdo -> prepare("DESCRIBE item");
    $statement -> execute();
    $columns = $statement -> fetchAll(PDO::FETCH_COLUMN);
    $column_exists = in_array($column, $columns);
    return $column_exists;
}

function table_exists($table, $pdo) {
    $statement = $pdo -> prepare("SHOW TABLES");
    $statement -> execute();
    $tables = $statement -> fetchAll();
    $table_exists = in_array($table, $tables);
    return $table_exists;
}
如果在“item”表中找不到作为列或作为表名的属性,则会引发异常

我的代码构造的准备好的语句如下所示:

$sql = "SELECT * FROM item WHERE cost = :cost
AND id IN (SELECT item_id FROM item_color 
WHERE color_id IN (SELECT id FROM color WHERE val = :color));";
然后就这样被处死了,

$statement = $pdo -> prepare($sql);
$statement -> execute(Array(":cost" => $cost, ":color" => $color));
我想知道的: 随着数据库的增长和访问频率的提高,我是否会遇到重大瓶颈?我的检索方法对一阶sql注入攻击安全吗

我所做的: 我已经阅读了基本的数据库设计原则和基本的sql注入攻击/防御方法。我试着阅读有关动态创建准备语句的内容,但我找到的材料不是我想要的。我已经用一个基本的测试了我的设计

为什么这个问题相关: 我读过的设计原则警告不要试图使数据库过于灵活,那些对该领域不熟悉的人没有办法衡量灵活性有多灵活,因此通过对该示例的分析可以从中受益。而且,准备好的语句似乎只打算用作静态模板。如果我发现这种动态构建它们的方法很吸引人,那么其他新手也可能会,所以我们需要知道我们是否正在创建一个巨大的安全漏洞。最后,我同时提出了这些问题,因为数据库设计和针对它运行的查询结构是直接相关的

详细信息: PHPV5.6.17
mysql v5.6.35

我对SQL的第一反应是,您确实需要学习如何在SQL中使用
JOIN
。连接操作是SQL和关系数据的基础。仅使用子查询代替
JOIN
就像使用另一种编程语言,但拒绝使用
while()
循环。当然,你能做到,但为什么

应该是

$sql = "
 SELECT i.id, i.name, i.cost, c.color 
 FROM item AS i
 INNER JOIN item_color AS ic ON i.id = ic.item_id
 INNER JOIN color AS c ON c.id = ic.color_id
 WHERE i.cost = :cost AND c.val = :color";
有关SQL连接的任何参考或教程

至于您关于安全性的问题,是的,使用查询参数相对于SQL注入来说是安全的。通过将基本查询硬编码并将动态部分分离为参数,可以消除不安全数据更改SQL查询解析的任何机会

您可能会喜欢我的演示文稿(视频:)


您的需求让我觉得您最好使用MongoDB这样的文档数据库,在这里您可以向任何文档添加属性。这并不意味着你在数据库设计上不必再谨慎,但它让你有机会在设计后更轻松地添加属性。

我认为问题可能是你可以通过猜测表和列来访问整个数据库。什么样的问题?你认为这会造成一个瓶颈吗?我真的不知道支票增加了多少开销。不,只是从安全的角度。如果有人尝试使用数据库用户、列密码怎么办?添加(某些)属性没有基本的设计问题。“太灵活”-如果您(例如)逾期或使用了一个新的系统,可能会出现问题。您正试图在数据库和应用程序之间建立一个灵活的层,主要的设计问题似乎是您将应用程序和该层混合在一起。幸运的是,人们已经创建了抽象数据库访问的“框架”(也允许灵活的列),请参见。您仍然需要做一些工作,但它应该解决您所有的问题。@LKKP4ThX我误解了您的评论。在上面的示例查询中,您将看到“SELECT*FROM item”是硬编码的,因此我认为我是安全的,除非我为注入攻击留下了一个开口。感谢您提供了这个伟大的示例。这是一个更具可读性的查询。我必须使用mysql。你知道有什么资源可以帮助我为这个数据库设计构建一个访问层吗?你可以尝试阅读MySQL 5.7中的JSON数据类型:你仍然可以在MySQL 5.6中以文本块的形式存储任何JSON,但是它不会像5.7数据类型那样存储得那么紧凑,你无法获得所有的函数来使用它,你不能用虚拟列对它进行索引。你可能还想阅读我的演示文稿。我明白了。将序列化lob方法添加到混合中将使检索特定项更加容易。
$sql = "
 SELECT i.id, i.name, i.cost, c.color 
 FROM item AS i
 INNER JOIN item_color AS ic ON i.id = ic.item_id
 INNER JOIN color AS c ON c.id = ic.color_id
 WHERE i.cost = :cost AND c.val = :color";