• Dangerous query method called with non-attribute argument(s)


    踩坑 query method。

    问题描述

    现有model issue,需要对issues进行排序,根据指定的ID集合来决定记录的位置,比如id包含在(4, 6, 9)中的纪录就排在前面,剩下的排在后面。

    使用scope进行处理:

    class Issue < ApplicationRecord
      .........
      IDLIST = [4, 6, 9]
      scope :order_by_custom_id, -> {
         order_by = ['CASE']
        order_by << "WHEN id in (#{IDLIST.join(', ')}) THEN 0"
        order_by << 'ELSE 1 END'
        order(order_by.join(' '))
      }
    end
    

    在controller中调用了该scope。刷新页面后,发现服务器报出warning message:

    DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "CASE WHEN id in (4,6,9) THEN 0 ELSE 1 END". Non-attribute arguments will be disallowed in Rails 6.0. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql().
    

    解决方法

    其实,报错信息里面已经告诉我解决方法了,但是当时一看懵逼,Dangerous query method?!直接Google了一堆,后面在slack上跟同事求助了下,搞定!

    很简单,就是使用warning message里面提到的Arel.sql()方法,将CASE WHEN id in (4,6,9) THEN 0 ELSE 1 END 用Arel.sql() 包起来即可。

    修改scope:

    class Issue < ApplicationRecord
      .........
      IDLIST = [4, 6, 9]
      scope :order_by_custom_id, -> {
         order_by = ['CA 大专栏  Dangerous query method called with non-attribute argument(s)SE']
        order_by << "WHEN id in (#{IDLIST.join(', ')}) THEN 0"
        order_by << 'ELSE 1 END'
        order(Arel.sql(order_by.join(' ')))
      }
    end
    

    OK!

    但是,这个Arel.sql(raw_sql)是什么?

    先看看Arel是什么。

    官方文档的解释:

    Arel is a SQL AST manager for Ruby. It

    • Simplifies the generation of complex SQL queries
    • Adapts to various RDBMSes

    文档里面还列出了很多例子,从简单的select * from users 到复杂点的joins table,我猜是因为我接触Rails的时间不长,反正是从来没用过这东西。

    Arel.sql(raw_sql) 这个类方法的源代码如下:

    def self.sql raw_sql
      Arel::Nodes::SqlLiteral.new raw_sql
    end
    

    也就是新建了一个Arel::Nodes::SqlLiteral实例,而Arel::Nodes::SqlLiteral为什么是安全的呢?用Arel::Nodes::SqlLiteral 把raw_sql包起来的用意是什么?估计也能猜到,防攻击啥的。果然,Google了下,发现说是可以防止SQL注入的情况。

    有些复杂了,脑子暂时消化不了。

    此外,文档中有关sanitize_limit 部分也有提到SQL injection的问题。

    参考

    Arel

    A “strict Arel” mode for ActiveRecord to prevent SQL injection vulnerabilities

  • 相关阅读:
    C#关于HttpClient的应用(二):融云IM集成
    C#关于HttpClient的应用(一):获取IP所在的地理位置信息
    PHP逐字符读取数据
    PHP逐行读取数据
    PHP函数的创建
    PHP数组的创建
    PHP基础学习代码案例
    查看端口号占用情况
    apache错误 Unable to open process" with PID 4!
    NUnit TestFixtureSetup 和 TestFixtureTearDown
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12239680.html
Copyright © 2020-2023  润新知