I've read about this for some time now on various SO threads, guides, etc... but all the answers are conflicting and contradictory.
It seems there's many similar methods, and a lot of the answers say to use a different one.
sanitize
sanitize_conditions
sanitize_sql
sanitize_sql_array
sanitize_sql_for_assignment
sanitize_sql_for_conditions
sanitize_sql_hash
sanitize_sql_hash_for_assignment
sanitize_sql_hash_for_conditions
sanitize_sql_like
I'm trying to write a 'raw query' adapter that lets me run raw Postgres queries, but allowing me to insert my own parameters that come from dangerous user input.
I can't use AR in these few instances because I'm doing complex lat/long calculations, aggregate functions, complex subqueries, etc.
So far I have tried 2 approaches:
Method 1
For this method, I don't know if sanitize
is the best option of the above, or if it will work in 100% of cases... (I'm using Postgres only)
class RawQuery
def exec(prepared, *params)
prepared = query.dup
params.flatten.each_with_index do |p, i|
prepared.gsub!("$#{i + 1}", ActiveRecord::Base.sanitize(p))
end
ActiveRecord::Base.connection.exec_query(prepared)
end
end
Trivial usage example (normally it wouldn't be this simple of course, or I would just use AR):
RawQuery.new.exec('SELECT * FROM users WHERE name = $1', params[:name])
Furthermore it seems that sanitize
delegates to quote
. But according to this SO post it says simply wrapping things with single quotes isn't secure... so I have no idea.
Method 2
I'm not sure if this is just as secure, but it seems to use an actual PG prepared function (which I assume is 100% secure). The only problem is rails doesn't print it out to the console, nor include the SQL execution time (which breaks my profiling tools).
class RawQuery
def prepare(query, *params)
name = "raw_query_#{SecureRandom.uuid.gsub('-', '')}"
connection = ActiveRecord::Base.connection.raw_connection
connection.prepare(name, query)
connection.exec_prepared(name, params)
end
end
Used the same way:
RawQuery.new.prepare('SELECT * FROM users WHERE name = $1', params[:name])
Is one method more secure over another? Are both 100% secure?
My apps always extend far outside of what Rails is capable of SQL-wise and I need a good lib I can include on all my projects which I know is completely safe.