Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

栏目: Ruby · 发布时间: 7年前

内容简介:Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

Ruby on Rails 是一个经典的 MVC 框架。其中,ActiveRecord 是 MVC 中的 M(模型),负责处理数据和业务逻辑。每一个数据库表对应创建一个类,类的每一个对象实例对应于数据库中表的一行记录,通常表的每个字段在类中都有相应的 Field。ActiveRecord 同时负责把自己持久化,在 ActiveRecord 中封装了对数据库的访问,即 CURD。

使用 ActiveRecord 执行 SQL 语句的大概顺序是:

  1. 把提供的查询方法转换为等价的 SQL 查询。
  2. 触发 SQL 查询并从数据库中检索对应的结果。
  3. 为每个查询结果实例化对应的模型对象。
  4. 当存在回调时,先调用 after_find 回调再调用 after_initialize 回调。

只要能够理解第一步中的转换规则,那么针对 ActiveRecord 的 SQL 注入和普通的 SQL 注入并没有什么区别。

然而,Rails 为 ActiveRecord 方法提供了内置的 SQL 过滤器,用于转义 '、"、NULL 和换行符,使得大部分 SQL 注入都失去作用。但这并不代表开发者写出来的代码就是绝对安全的。如果没有对用户输入手动进行过滤,并且错误运用了某些方法,那么仍然存在 SQL 注入的风险。具体来讲,在使用某些方法时,需要手动触发这个过滤器。

所谓“错误使用“指的是,向某些方法传入 String 而不是 Array 或 Hash。因为在这种情况下,过滤器不会被触发。

where

以常用的 where 方法作例子,它能够接受的参数类型有 string,array 和 hash。然而,过滤器只有当传入的参数是 array 或 hash 时才是生效。如果开发者直接传入一个 string 类型的参数,那么会带来严重的安全隐患,看下面这个例子:

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

其中,params[:name]和params[:password] 是表单提交的用户名和密码。转换后的 SQL 语句为:

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

如果输入的 name为“') OR 1=1--“,那么 SQL 语句就会变成:

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

“OR 1”后面的内容全部被注释掉了,这是很常见的一句话密码,它和不使用 ORM 的情况下SQL 注入的 PAYLOAD 并无二异。

安全的写法如下:

  1. 传入 Array:
    Rails 中 ActiveRecord 的不当使用产生 SQLI 风险
  2. 或者传入 Hash:
    Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

这两种情况下过滤器会被触发,输入的引号会被转义引起报错:

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

find_by

同理,find_by 方法也有相同的问题,因为它等价于 where(*args).take:

params[:id] = "admin = '’ OR 1=1 )#"
User.find_by params[:id]

SQL 语句:

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

最安全的方式是传入 Hash:

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

Select/pluck

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

select 方法用于指定查询字段,如果传入的是 String,那么输入完全不会被转义:

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

SQL:

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

需要注意 select 方法返回的是 Model 类。

pluck 方法和 select 方法作用的地方一致,唯一的不同是 pluck 方法返回一个数组。 Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

等价于:

Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

因为 select 和 pluck 方法作用于 SQL 语句的最开始,因此 SQL 注入的方式非常灵活。

delete_all/destroy_all/update_all

这三个批量操作方法都可以进行 SQL 注入,只要传入的参数是 String。

delete_all 和 destroy_all 的区别是 destroy_all 会触发 ActiveRecord 的回调,而 delete_all 会直接把 SQL 语句传给数据库,所以理论上 destroy_all 比 delete_all 更安全一点。总之,正确的使用方法是传入 Hash。

  1. delete_all/destroy_all:
    Rails 中 ActiveRecord 的不当使用产生 SQLI 风险
  2. SQL 语句:
    Rails 中 ActiveRecord 的不当使用产生 SQLI 风险
  3. update_all:
    Rails 中 ActiveRecord 的不当使用产生 SQLI 风险 SQL 语句:
    Rails 中 ActiveRecord 的不当使用产生 SQLI 风险
  4. From

    from方法指定查询的表明,也就是注入点在from之后:

    params[:from] = "users WHERE admin = 't' OR 1=1 #"
    User.from(params[:from]).where(admin: false)

    SQL语句:

    SELECT "users".* FROM users WHERE admin = 't' OR 1=1 #WHERE "users"."admin" = ?

    后面的where被截断了。

    Calculate

    指的是 ActiveRecord::Calculations#calculate 中的方法,对应于 SQL 语法中的聚集函数

    包含有:

    1. average
    2. calculate
    3. count
    4. maximum
    5. minimum
    6. sum

    注入点是 select 和 from 之间:

    Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

    SQL 语句:

    Rails 中 ActiveRecord 的不当使用产生 SQLI 风险

    Group/Order/Having/Reorder

    这几个方法对应 SQL 中的 排序 和分组子句,group 方法对应于 group by 子句;having 对应于having 子句;oreder 和 reorder 对应于 order by 子句(reorder 是用于覆盖作用域的默认排序,所以它们的注入方法是完全一样的)。

    1. 在 error-based 或 bool 类型的 SQL 注入中,分组和排序子句可以用于猜测字段数:
      select * from user order by 1,2,3; (假设 user 表只有两个字段)
      如果开启了错误提醒,那么字段名会直接显示在错误中。
      其它情况下,可以根据返回的页面是否正确来判断。
    2. 当然也可以直接爆数据:
      params[:sortby] = "(CASE SUBSTR(password, 1, 1) WHEN 's' THEN 0 else 1 END)" User.order("#{params[:sortby]} ASC")

    SQL 语句:

    SELECT "users".* FROM "users" ORDER BY (CASE SUBSTR(password, 1, 1) WHEN 's' THEN 0 else 1 END) ASC

    (猜解 password 的第一位是否为’s’,根据返回的是 True 还是 False ,排序的结果会有所不同)

    还有一些方法如 lock,joins 也存在注入点,但因为在实际情况下难以利用或者跟前文的利用方法有重复,故不展开介绍。

    小结

    总的来说对于 ActiveRecord 的 SQL 注入和普通的 SQL 注入其实差别并不是很大,关键在于掌握 query methods 到 SQL 语句的转换规则以及了解 SQL 过滤器的触发条件。从以上的那些例子可以很明显得看出,当传入的参数是 String 时,许多方法是不会触发 SQL 过滤器的,这时的 SQL 注入就和普通的 SQL 注入基本没有区别。

    攻击者应该了解哪些方法可能存在 SQL 注入漏洞。然而实战时的难点主要在于判断 SQL 查询使用的方法,因为链式方法的灵活性,同样的 SQL 查询可以有很多种写法,这对于 SQL 注入带来了很大的困难。

    而对于 Rails 开发者来说,应当切记不要直接向查询方法直接传入 String,而应使用 Array 和 Hash,只要能做到这一点,那么被 SQL 注入的可能性将会大幅降低。

    --------

    微信公众号:TwoSecurity (二向箔安全)


以上所述就是小编给大家介绍的《Rails 中 ActiveRecord 的不当使用产生 SQLI 风险》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数码人类学

数码人类学

[英]丹尼尔·米勒、希瑟·A.霍斯特 / 王心远 / 人民出版社 / 2014-10 / 48.00元

人类学有两大任务,一是理解什么是人,二是理解人性是如何透过多元的文化表现出来。数码科技的蓬勃发展给这两者都带来了新的作用力。《数码人类学》向读者展示了人类与数码科技如何辩证地相互定义。最终我们试图得出一个结论,那便是“数码科技对人类到底意味着什么?” 从社交网站到数字化博物馆;从数字时代政治学到电子商务,浸润式的数码科技,给普通人的生活带来了根本性的改变。仅仅用数据来说明与理解问题显然过于太......一起来看看 《数码人类学》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具