【问题标题】:Securely escaping dynamic table names in MySQL using Codeigniter使用 Codeigniter 安全地转义 MySQL 中的动态表名
【发布时间】:2012-07-16 19:16:39
【问题描述】:

我遇到了一个小问题。我目前正在开发一个需要在 MySQL 中使用动态表名的应用程序。

基本上,我有一个基于多种因素(流派、播放长度、发行日期等)从数据库中选择专辑的过程——这个过程的一部分允许用户创建一堆自定义过滤器..

自定义过滤器会向用户返回该选择条件内所有专辑的计数。然后将这些专辑的 ID 存储在一个带有随机生成的哈希/序列号的表中(例如,albumSelect_20880f9c05d68a)

我这样做是因为我不想在一个字段中存储一个巨大的逗号分隔列表(真的很傻)——而且我不想像这样将一组值发送到我的 HTML 中的隐藏字段只会增加数据吞吐量(一次可能是数千行)

在 CodeIgniter 中,我使用查询绑定来生成我的 SQL 查询,如下所示:

select * from artists where artistName = ? AND albumTitle = ?

当我参数化查询时,查询会自动转义

$query = $this->db->query($sql,array("Singer","Album"));

现在是棘手的部分

如果我将查询编写成如下所示:

$sql = "select albumid from albums where albumid in (select albumid from albumSelect_?)";
$this->db->query($sql,array('20880f9c05d68a'));

结果查询变为:

select `albumid` from `albums` where `albumid` in (select `albumid` from `albumSelect_'20880f9c05d68a'`)

确实如此,但显然查询无效..

编辑:更多信息

查询可能是更大查询的一部分,具体取决于用户选择的条件。例如

$sql = "select albumid from albums where albumid in(select albumid from tags where tag = ?) AND albumid in(select albumid from albumSelect_?)";

我只是想知道是否有办法让它工作,或者是否有人可以提出更好的替代方案。表名的连接显然不是一个选项。

提前致谢!

戴夫

【问题讨论】:

  • 如果您对数据进行了规范化,则不需要这样做存储一个逗号分隔的专辑列表。这称为“具有多通性”关系。

标签: php mysql security codeigniter activerecord


【解决方案1】:

转义机制仅适用于数据字符串,不适用于模式名称。换句话说,只针对表的内容,而不针对其结构。因此,您要么必须自己将字符串粘贴到查询中,要么避免以这种方式使用表。查询模板的? 对此无济于事。

如果将字符串粘贴到表名中,则可以使用通常的 PHP 字符串连接机制。您应该格外确定对照适当严格的正则表达式检查字符串,以避免 SQL 注入。确保您真的只粘贴您生成的格式的单个随机字符串,而不是其他任何内容。

作为替代方案,您可以拥有一个包含所有选择的大表,并使用额外的列来保存您的标识散列,或使用其他合适的键来标识单个选择。这样,您就不必在正常操作期间修改数据库模式。我相信大多数开发人员,包括我在内,都宁愿避免通过程序代码进行此类修改。良好的数据库设计适用于固定架构。

【讨论】:

  • 嗨 MvG,我决定按照您的建议创建一张高桌。无论如何,这样做实际上更适合预期的工作流程,老实说,我不知道为什么我首先想到以另一种方式做。感谢您的帮助!
【解决方案2】:

听起来你想使用动态 SQL。您可能不得不走prepared statements 的道路。使用它们,您可以在字符串上调用PREPARE,然后调用EXECUTE。正常的连接工作得很好。

这应该允许您将 SQL 构建为字符串并执行它。如果将 CodeIgniter 的参数化与 MySQL 存储过程结合使用,则可以调用类似 "CALL selectAlbums(?, ?)" 的查询(假设 selectAlbums 是包含实际查询的 PREPARE 的存储过程),它将返回集合。

如果你想去掉输出中的's,通过CONCAT来引导参数,这将产生一个正常的字符串。

【讨论】:

  • 准备好的语句不适用于此类事情。它们使用正常的语句语法,因此它们不会更容易地使用动态表名。准备好的语句只是通过缓存给定语句的执行计划来提高性能的一种方式,因此服务器已经知道如何计算给定类型的结果。
  • 不,这正是你可以用它们做的。文档中甚至还有一个使用字符串变量作为表名的示例。请阅读。你在谈论存储的例程。或者,也许是 CodeIgniter 的“prepared statements”,它是 MySQL API 的prepared statements,而不是引擎中集成的动态 SQL 机制。那里有很大的不同。
  • 好吧,我的错。我想到了 C API,并认为服务器端准备好的语句语言元素几乎可以做同样的事情。它们似乎在很多方面都可以做到,但字符串和服务器端CONCAT 的使用开辟了新的途径。对不起这里的噪音。我真的应该比我多读两句话。
猜你喜欢
  • 2012-10-04
  • 1970-01-01
  • 2021-07-04
  • 2011-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多