4

我正在开发一个相对较小的应用程序来与 PostgreSQL 对话,并希望获得一些反馈,说明在防止 SQL 注入方面还有多远。

该应用程序在 Perl 中,不使用任何 ORM 模块(仅 DBI)。SQL 语句是用占位符以典型方式构造的:

my $sql = "SELECT * FROM $cfg->{tablename} WHERE foo = ?";
my $sth = $dbh->prepare($sql);
$sth->execute('bar');

插入表名的原因是应用程序必须对多个表执行相同的操作,所有表都有一个列“foo”。

使用 ?占位符可防止大多数简单的 SQL 注入攻击。我的问题是关于表名,你不能使用占位符。该表来自配置文件,但应用程序支持 --configfile 开关以使用备用配置文件。

数据库凭据存储在配置文件中。因此,如果攻击者可以使用 $cfg->{tablename} 替换为恶意内容的配置文件(或替换默认文件),则可能会“诱骗”应用程序运行恶意代码。

对于攻击者来说,他们必须已经拥有有效的数据库凭据,否则应用程序将无法连接。如果他们有凭据,那么他们可以使用 DBI 编写自己的代码或使用 psql cli 执行恶意操作。

我看到了两种可能的方法来防止这种情况:

  • 切换到 ORM,在这种情况下,我会按照 $orm->get_class_for_table($cfg->{tablename}
  • 在准备 SQL 语句之前使用正则表达式清理表名
  • 使用 $dbh->quote_identifier()

显然第二种方式是“便宜又快乐”的方式。但是鉴于上面关于凭据的声明,这些方法中的任何一种真的有必要吗?在迫使攻击者只使用备用攻击向量(与实际阻止攻击的努力相反?

4

2 回答 2

10

使用quote_identifier

my $sql = "SELECT * FROM ".
  $dbh->quote_identifier($cfg->{tablename}).
  " WHERE foo = ?";
于 2009-07-03T08:50:33.040 回答
1

在这些情况下,我制作自己的占位符版本,并检查我将作为表名插入的值,以确保它是我期望的表名。这意味着不仅仅是检查表是否存在;某些操作应该只影响某些表而不影响其他表。

我不会使用正则表达式来清理名称。要么他们做对了,它在你的允许名称列表中,要么他们弄错了,你给他们一个错误。

于 2009-08-07T02:53:57.803 回答