安全地转义表名/列名

Posted

技术标签:

【中文标题】安全地转义表名/列名【英文标题】:safely escaping table names/column names 【发布时间】:2012-10-04 23:00:57 【问题描述】:

我在 php 中使用 PDO,因此无法使用准备好的语句转义表名或列名。以下是我自己实现它的万无一失的方法吗:

$tn = str_replace('`', '', $_REQUEST['tn']);
$column = str_replace('`', '', $_REQUEST['column']);
$sql = "SELECT * FROM `tn ` WHERE `column` = 23";
print_r(
    $pdo->query($sql)->fetchAll()
);

或者还有一些可以攻击的途径?

【问题讨论】:

@Petah 我需要在添加更多表后能够使用这个类,而不必不断更新白名单 向数据库询问有效列名的列表,如果每个请求的两个查询存在问题,则缓存它们。如果你允许用户输入列名,你可能需要改变你的数据库设计。 【参考方案1】:

您可以通过询问数据库哪些列对给定数据库表有效来使用动态白名单。这是一个额外的sql查询,但安全性很好。

select COLUMN_NAME 
from INFORMATION_SCHEMA.COLUMNS 
where TABLE_SCHEMA = :databaseName
  and TABLE_NAME = :tableName

获取结果,然后确保所有动态列名都在结果集中。

我相信视图包含在INFORMATION_SCHEMA.COLUMNS 中,所以它应该都可以正常工作。

然后,在组装动态 sql 时,只需在已验证的列名周围使用反引号(我假设您使用纯 ascii 列名,否则您可能会有其他考虑)。

【讨论】:

这将导致每次调用都有两个数据库调用。我正在寻找可以清理表和列名而不是白名单的东西。我真的很想知道我可以通过的极限。例如,我知道我可以通过a-zA-Z0-9_. 离开其他字符呢? 你已经在犯错误了(句号是不允许的,见dev.mysql.com/doc/refman/5.0/en/identifiers.html)除非你真的明白你在做什么,包括对字符集和unicode有很好的理解,只要使用白名单就不用担心了关于你没有的性能问题。或者,将表和列名称限制为长度有限的 a-zA-Z0-9_ 以使其易于验证。避免使用 unicode 和非 ascii 字符。 每个人都这么说,但为什么呢?如果我有这样的事情会发生什么(waitforitwaitforit):"``" . preg_replace('#``|--#', '', $input) . "``"(两个``表示一个) 每个人都一直这么说,因为他们知道有些事情太复杂而无法打扰。如果你愿意,你可以谷歌多字节字符集 sql injection 来了解它是如何完成的,但除非你了解多字节编码,否则它不太可能有意义。很多漏洞只有在某些特定条件下才有可能。 如果您要获取列列表,您可能希望使用键值缓存来加快对其的访问速度(它不会改变)。

以上是关于安全地转义表名/列名的主要内容,如果未能解决你的问题,请参考以下文章

将列名转义为查询参数

如何使用 Java 在 PostgreSQL 中安全地转义 SQL 的任意字符串

如何使用 XSL 转义 XML 内容以安全地将其输出为 JSON?

如何安全地为 bigquery 节点插入转义用户输入?可以在 bigquery.insert 节点库上使用参数化查询吗?

Spark 1.6:在 DataFrame 中使用转义的列名删除列

在 Rails 上为连接、限制、选择等(不是条件)的 SQL 片段安全地转义字符串