5

モデルにスコープがあります:

scope :assigned_to_user, ->(user) {
task_table = UserTask.table_name

    joins("INNER JOIN #{task_table}
          ON  #{task_table}.user_id = #{user.id}
          AND (#{task_table}.type_id = #{table_name}.type_id)
          AND (#{task_table}.manager_id = #{table_name}.manager_id)
        ")
}

したがって、breakman レポートを実行すると、次の警告が表示されます。

assigned_to_user | SQL Injection | Possible

だから私は次のことを試しました:

scope :assigned_to_user, ->(user) {
    task_table = UserTask.table_name

        joins(ActiveRecord::Base::sanitize("INNER JOIN #{task_table}
              ON  #{task_table}.user_id = #{user.id}
              AND (#{task_table}.type_id = #{table_name}.type_id)
              AND (#{task_table}.manager_id = #{table_name}.manager_id)
            "))
    }

'SQLの前後に(アポストロフィ)を追加するため、これはうまくいきません。したがって、これをいくつかの結果を返すクエリの一部として使用し、このスコープを適用すると、間違った SQL が生成されます。

私もこれを試しました:

scope :assigned_to_user, ->(user) {
    task_table = UserTask.table_name

        joins("INNER JOIN #{task_table}
              ON  #{task_table}.user_id = ?
              AND (#{task_table}.type_id = #{table_name}.type_id)
              AND (#{task_table}.manager_id = #{table_name}.manager_id)
            ", user.id)
    }

ステートメントも作成しません。そして、機能せず、言及する価値さえない他のいくつかのものを試しました。これを修正する方法を知っている人はいますか?

4

1 に答える 1

6

ここで何らかの調査を行った後、私が使用するものです。sanitize_sql_array( ref )と呼ばれるメソッドがあり、次のように SQL 文字列と置換値を渡すことで、ステートメントをエスケープするために使用できます。

sanitize_sql_array(['user_id = :user_id', user_id: 5])
# => "user_id = 5"

このメソッドにテーブル名を渡すと、それもエスケープされますが、オブジェクトのquoteメソッドがActiveRecord::Base.connection値に適用されます。これは、変数をエスケープするために使用されますが、テーブル名には使用されません。時々うまくいくかもしれませんが、PostrgreSQLを使用していたときは失敗しました。quoteメソッドは一重引用符を使用していますが、PostgreSQLではテーブル名に二重引用符が必要だからです。

sanitize_sql_array([
  'INNER JOIN :table_name ON :table_name.user_id = :user_id',
  { table_name: 'users', user_id: 5 }
])
# => "INNER JOIN 'users' ON 'users'.user_id = 5"

connectionオブジェクトにはメソッドもあり、quote_table_nameテーブル名に個別に適用して、それらがエスケープされていることを確認し、sanitize_sql_arrayユーザー ID に使用できるようにします。

scope :assigned_to_user, -> (user) {
  task_table = connection.quote_table_name(UserTask.table_name)
  current_table = connection.quote_table_name(table_name)
  sanitized_sql = sanitize_sql_array([
    "INNER JOIN #{task_table}
    ON  #{task_table}.user_id = :user_id
    AND (#{task_table}.type_id = #{current_table}.type_id)
    AND (#{task_table}.manager_id = #{current_table}.manager_id)",
    { user_id: user.id }
  ])
  joins(sanitized_sql)
}

または、メソッド call ( )ですべてをラップする代わりに、実際にsanitizeonを使用することもできます。user.idsanitize_sql_array#{sanitize(user.id)}

ちなみに、クエリは変数に移動されているため、Brakeman はまだ警告を表示していません。Brakeman は文字通りコードをそのまま解析し、変数とその内容については知りません。したがって、これはすべて、すべてがエスケープされていることを確認するためのものです。

Brakeman を黙らせるには、クエリを変数に移動するだけです。

scope :assigned_to_user, -> (user) {
  task_table = UserTask.table_name
  query = "INNER JOIN #{task_table}
          ON  #{task_table}.user_id = #{user.id}
          AND (#{task_table}.type_id = #{table_name}.type_id)
          AND (#{task_table}.manager_id = #{table_name}.manager_id)"
  joins(query)
}
于 2015-01-09T21:20:38.270 に答える