避免通过 ActiveRecord::Base.connection.execute 查询进行 sql 注入



我需要按方法查询ActiveRecord::Base.connection.execute(USER_INPUT)

查询字符串由 USER INPUT 给出(他们可以通过任何time period的 URL 查询,product_type

如何防止 SQL 注入?为了避免对我的系统造成任何损坏?

是否可以限制用户只能查询除DELETE, TRUNCATE, INSERT, UPDATE ...之外的SELECT

如果我正确理解你想要什么,你实际上根本不想阻止SQL注入。事实上,你允许你的应用在设计上运行任意 SQL。

您似乎想要的是限制可以运行的 SQL

这注定要失败。至少在PostgreSQL上,SELECT可以运行各种不希望普通用户运行的功能,如果使用特权用户调用。他们还可以访问包含您不一定希望他们知道的信息的系统目录。

即使成功编写了阻止在单个 SQL 字符串中包含多个命令的分析器,按命令类型筛选也将不起作用。这并不像您希望的那么简单;您必须处理文字、$$引用、标识符引用、--/* */注释等的打开和关闭standard_conforming_strings你会弄错,在你的过滤器上有洞和/或禁止完全合法的命令。

一种稍微安全一点的方法是在运行来自用户的命令时使用特权较低的数据库角色。此角色应仅有权阅读您明确GRANT的内容。它不应该有INSERTUPDATEDELETE权限,没有表或其他对象所有权,当然也不是超级用户。你让用户发送他们想要的任何SQL,或者粗略地尝试过滤它,但你依靠数据库的访问权限来真正阻止他们做任何顽皮的事情。您也可以SET TRANSACTION READ ONLY...但请注意,这样的设置主要是建议性的,而不是硬性限制。

据我所知,Rails并不容易获得非特权连接,或者让你的应用程序每天使用比升级更不特权的连接。这是因为 Rails 喜欢以单个数据库用户的身份做所有事情,通常是拥有所有对象的高特权用户,因此可以随时进行迁移。这都是Rails/ActiveRecord哲学的一部分,即数据库只不过是一个愚蠢的行存储。

即使使用更灵活的框架,与不同的用户权限建立连接仍然很痛苦。 SET ROLESET SESSION AUTHORIZATION工作,但两者都可以重置以获得特权连接,目前没有在PostgreSQL中放弃特权的概念。用户可能潜入RESET ROLERESET SESSION AUTHORIZATION的方式太多了,我无法在任意SQL中使用它们。因此,您必须实际使用不同的凭据建立新连接。

这就是我要做的。 使用不同的凭据建立新连接,并以非常受限制的用户帐户运行 SQL。您可以执行一些操作,例如REVOKE从此帐户查看pg_procpg_class的功能,限制它可以看到的系统目录量,并且您可以仅授予它对表的最小访问权限,而您确实需要它拥有。(请记住REVOKE CREATE ON SCHEMA public FROM public然后将其GRANT回您希望能够制作表格的用户)。

我认为您正在寻找的是报价

sql = ActiveRecord::Base.connection.quote( potentially harmful string )
res = ActiveRecord::Base.connection.execute(sql)

您还可以使用sanitize_sql_array:

sql = ActiveRecord::Base.send(:sanitize_sql_array, sql_array)
res = ActiveRecord::Base.connection.execute(sql)

我在尝试在自己的应用程序中创建一种"数据剪辑"(Heroku 样式)时遇到了类似的问题。尽管我将我的问题陈述为"如何让我的应用程序的用户以只读模式运行任意 SQL"。

不需要特定数据库用户的最优雅的解决方案是:

ActiveRecord::Base.transaction do
  results = ActiveRecord::Base.connection.select_all sql
  do_your_stuff_here_with results
  raise ActiveRecord::Rollback
end

引发 ActiveRecord::回滚将回滚事务,防止保留任何内容,例外情况是在事务块之外不重新引发。

该select_all防止使用多个语句,因为它处理 libpq 中的预准备语句接口。

我会在该数据库上创建另一个仅授予运行SELECT查询权限的用户。然后使用此受限用户帐户运行从用户输入生成的查询。

最新更新