问题: 我的任务是创建一个数据库来保存有关各种产品的信息,并创建 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 |
+---------+----------+
'item' 表可能会在以后添加列,并且可能还会添加更多联结表。
检索产品的请求需要 http://www.example.com/api/products?color=purple&cost=50 使用 php,我正在动态构建准备好的语句来检索相关产品,希望不会为 sql 注入(inject)打开大门。首先,我使用以下函数确定哪些属性包含在“项目”表中,哪些属性位于单独的表中:
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 注入(inject)攻击安全吗?
我做了什么: 我已经阅读了基本的数据库设计原则和基本的 sql 注入(inject)攻击/防御方法。我试图阅读有关动态创建准备好的语句的信息,但我找到的 Material 并不是我要找的。我已经针对基本 Bobby Tables attack 测试了我的设计.
为什么这个问题是相关的: 我读过的设计原则警告不要让数据库过于灵活 那些刚接触该领域的人没有办法判断灵活程度有多灵活,并且可以从对这个例子的分析中获益。此外,准备好的语句似乎只打算用作静态模板。如果我发现这种构建它们的动态方式很诱人,那么其他新手可能也会如此,所以我们需要知道我们是否正在创建一个很大的安全漏洞。最后,我一起问了这些问题,因为数据库设计和要针对它运行的查询的结构直接相关。
详细信息: PHP v5.6.17 mysql v5.6.35
最佳答案
我对您的 SQL 的第一 react 是您确实需要学习如何在 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 注入(inject)是安全的。通过对基本查询进行硬编码并将动态部分分离到参数中,您可以消除不安全数据更改 SQL 查询解析的任何机会。
您可能会喜欢我的介绍 SQL Injection Myths and Fallacies (视频:https://www.youtube.com/watch?v=VldxqTejybk)。
您的要求让我认为您最好使用像 MongoDB 这样的文档数据库,您可以在其中向任何文档添加属性。这并不意味着您仍然不必对数据库设计保持谨慎,而是让您有机会更轻松地在设计后添加属性。
关于php - 具有动态准备语句的安全、可扩展数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46819389/
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca
我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#
我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。
在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?
我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_