我需要通过方法ActiveRecord::Base.connection.execute(USER_INPUT)
查询字符串由 USER INPUT 提供(他们可以通过网址查询任意time period
,product_type
)
如何阻止SQL注入?为了避免对我的系统造成任何损害?
是否可以限制用户只能查询除SELECT
DELETE, TRUNCATE, INSERT, UPDATE ...
答案 0 :(得分:4)
如果我理解你想要什么,你实际上根本不想阻止SQL注入。实际上,您允许应用程序按设计运行任意SQL。
您似乎想要限制可以运行的 SQL。
这注定要失败。至少在PostgreSQL上,SELECT
可以运行您不希望普通用户运行的各种功能(如果使用特权用户调用)。他们还可以访问系统目录,其中包含您不一定希望他们知道的信息。
即使您成功编写了一个防止在单个SQL字符串中包含多个命令的解析器,按命令类型进行过滤也无法正常工作。这并不像你希望的那么简单;您必须为文字处理standard_conforming_strings
,$$
引用,标识符引用,--
和/* */
评论等等。您将获取它错误并在您的过滤器中有漏洞和/或禁止完全合法的命令。
一种稍微安全的方法是在从用户运行命令时使用权限较低的数据库角色。此角色应该只有权阅读您明确GRANT
的内容。它应该没有INSERT
,UPDATE
或DELETE
权限,没有表或其他对象所有权,当然也不是超级用户。您让用户发送他们想要的任何SQL,或者粗略地尝试过滤它,但您依靠数据库的访问权限来真正阻止他们做任何顽皮的事情。您也可以SET TRANSACTION READ ONLY
...但请注意,这样的设置主要是建议性的,而不是严格限制。
据我所知,Rails不容易获得非特权连接,或者让您的应用程序日常使用权限较低的连接而不是升级。这是因为Rails喜欢将所有内容都作为单个数据库用户执行,通常是拥有所有对象的高权限用户,因此只要感觉就可以进行迁移。它是Rails / ActiveRecord理念的一部分,数据库不仅仅是一个哑行存储。
即使使用更灵活的框架,获得与不同用户权限的连接仍然很痛苦。 SET ROLE
或SET SESSION AUTHORIZATION
工作,但两者都可以重置以获得特权连接,目前还没有删除PostgreSQL中的权限的概念。有太多方法可以让用户潜入RESET ROLE
或RESET SESSION AUTHORIZATION
,以便我习惯使用任意SQL。因此,您必须使用不同的凭据实际建立新连接。
这就是我的所作所为。使用不同的凭据建立新连接,并将SQL作为非常受限制的用户帐户运行。您可以执行REVOKE
从此帐户查看pg_proc
和pg_class
的权限,限制它可以查看的系统目录的数量,并且您只能授予它最少的访问权限。你真正需要它的桌子。 (请记住REVOKE CREATE ON SCHEMA public FROM public
然后GRANT
返回给您希望能够制作表格的用户。“
答案 1 :(得分:1)
我认为你要找的是quote
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)
答案 2 :(得分:1)
我遇到了类似的问题,试图在我自己的应用程序中创建一种“dataclips”(Heroku风格)。虽然我会将我的问题说成“如何让我的应用程序的用户以只读模式运行任意SQL”。
无需特定数据库用户的最优雅解决方案是:
ActiveRecord::Base.transaction do
results = ActiveRecord::Base.connection.select_all sql
do_your_stuff_here_with results
raise ActiveRecord::Rollback
end
引发ActiveRecord :: Rollback将回滚事务,防止任何事情被持久化,异常不会在事务块之外重新引发。
select_all阻止使用多个语句,因为它处理libpq中的预准备语句接口。
答案 3 :(得分:0)
我会在该数据库上创建另一个用户,该用户仅授予运行SELECT
查询的权限。比使用此受限用户帐户运行从用户输入生成的查询。