2017-10-18 106 views
3

问题扩展的数据库: 我的任务是创建一个数据库来保存关于各种产品信息,并创建RESTful API的服务和管理这些信息。但客户并不确切知道他们在这些产品上需要的所有信息,因此数据库可能会在后面添加新的列和表以适应新的产品属性。我的问题是生产一个数据库,它将随时接受这些更改并构建查询,以便根据产品属性安全地获取产品,这些产品属性尚不存在,几乎没有修改。安全,动态准备语句

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

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

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

+--------------------+ 
|  item_color | 
+---------+----------+ 
| item_id | color_id | 
+---------+----------+ 
|  0 |  0 | 
|  0 |  1 | 
+---------+----------+ 

“项目”表可能会在稍后添加列,并且可能还会添加更多结点表。

检索产品的请求需要http://www.example.com/api/products?color=purple&cost=50 使用php我正在动态构建准备好的语句以检索相关产品,希望不需要打开sql注入的大门。首先,我确定哪些属性都包含在“项目”表,并使用以下的函数,它们在不同的表:

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; 
} 

如果该属性没有发现如在“项”表中的列或作为表名称,然后抛出异常。

预处理语句我的代码结构看起来像:

$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注入攻击/防御方法。我试着阅读关于动态创建预准备语句的内容,但是我找到的材料并不是我正在寻找的内容。我已经通过基本的Bobby Tables attack测试了我的设计。

为什么这个问题是相关的: 的设计原则,我读过警告不要试图让数据库太灵活了这些新的领域有没有办法来衡量是很灵活的过于灵活,可以从分析中获益这个例子。另外,似乎准备好的语句仅用作静态模板。如果我发现这种动态的方式来构建它们,那么其他新手可能也会这样,所以我们需要知道我们是否正在创建一个很好的安全漏洞。最后,我一起提出了这些问题,因为数据库设计和针对它运行的查询的结构是直接相关的。

详情: PHP v5.6.17 MySQL的V5.6。35

+0

我认为一个问题可能是您可以通过猜测表和列来访问整个数据库。 – LKKP4ThX

+0

什么样的问题?你认为这会造成一个瓶颈吗?我真的不知道这些支票增加了多少开销。 –

+0

不,只是从安全方面。如果有人尝试数据库用户,列密码怎么办? – LKKP4ThX

回答

0

我对你的SQL的第一反应是你真的需要学习如何在SQL中使用JOIN。连接操作对于SQL和关系数据非常重要。仅使用子查询代替JOIN就像使用其他编程语言,但拒绝使用while()循环。当然,你可以做到这一点,但为什么呢?

$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));"; 

应该

$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查询解析的机会。

您可能会喜欢我的演示文稿SQL Injection Myths and Fallacies(视频:https://www.youtube.com/watch?v=VldxqTejybk)。

您的要求让我觉得您最好使用像MongoDB这样的文档数据库,您可以在其中为任何文档添加属性。这并不意味着您不必对数据库设计小心,但它使您可以更轻松地在设计之后添加属性。

+0

谢谢你的好例子。这是一个更可读的查询。我必须使用mysql。你知道有哪些资源可以帮助我构建数据库设计的访问层吗? –

+0

您可以尝试阅读关于MySQL 5.7中的JSON数据类型:https://dev.mysql.com/doc/refman/5.7/en/json.html –

+0

这看起来很神奇!不幸的是,我正在使用MySQL 5.6 .. –