Home > Net >  Is 'Arel::Nodes::Quoted' the best way to avoid injection when using 'NamedFunctions&#
Is 'Arel::Nodes::Quoted' the best way to avoid injection when using 'NamedFunctions&#

Time:08-17

I was developing a specific filter when I ran into the following question:

input_from_user = Arel::Nodes::Quoted.new(input_from_user.split('.').second)
separator = Arel::Nodes::Quoted.new('.')

Model.where(Arel::Nodes::NamedFunction.new('split_part', [input_from_user, separator, 2]).eq('random_value'))

This works, but I am not sure if this is really secure, I know that 'Arel.sql' or 'Literal' would not garantee any security, 'Quoted' node seems to handle injection, but I am not 100% into injection security, is there any other way to write this? (which does not involves creating fields on the database) if not, is this safe?

CodePudding user response:

TL;DR:

Yes these will be escaped accordingly, just as they would be for higher level AR query methods.

Explanation:

So here is how Nodes::NamedFunction will work in SQL compilation (in a nut shell):

  1. visit the Nodes::NamedFunction (Source)
  2. Visit each expression (your Array argument) (Source)
  3. Since they are Nodes::Quoted visit those expressions (Source)
  4. Use quote method (Source)
  5. Use Postgres Adapter quote method (Source)
  6. Use Abstract Adapterquote method because these are Strings (Source)
  7. Use Postgres Adapter quote_string to escape strings (Source)
  8. Use Postgres connection escape method (from the pg gem) (Source or Docs because they are easier to read)

The result will be split_part('input_from_user','.',2).

Additional Notes:

  1. Your only other issue is that your where does not have an queryable expression (no predication) of any kind so you would need to modify this to something like the following (which will generate an Arel::Nodes::Equality object)
Model.where(
  Arel::Nodes::NamedFunction.new(
    'split_part', 
    [input_from_user, separator, 2]
  ).eq('sub string'))
  1. Arel::Nodes provides a convenience method (build_quoted) that reads a little nicer. e.g.
input_from_user = Arel::Nodes.build_quoted(input_from_user.split('.').second)
separator = Arel::Nodes.build_quoted('.')

Model.where(
  Arel::Nodes::NamedFunction.new(
    'split_part', 
    [input_from_user, separator, 2]
  ).eq('sub string'))
  • Related