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):
- visit the
Nodes::NamedFunction
(Source) - Visit each expression (your Array argument) (Source)
- Since they are
Nodes::Quoted
visit those expressions (Source) - Use
quote
method (Source) - Use Postgres Adapter
quote
method (Source) - Use Abstract Adapter
quote
method because these areString
s (Source) - Use Postgres Adapter
quote_string
to escape strings (Source) - Use Postgres connection
escape
method (from thepg
gem) (Source or Docs because they are easier to read)
The result will be split_part('input_from_user','.',2)
.
Additional Notes:
- 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 anArel::Nodes::Equality
object)
Model.where(
Arel::Nodes::NamedFunction.new(
'split_part',
[input_from_user, separator, 2]
).eq('sub string'))
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'))