DEV Community

DEV Community

nicklevenson

Posted on May 21, 2021

Sanitizing SQL in Rails/ActiveRecord

ActiveRecord methods are great for easily querying your database. However, at some point you'll probably have to implement custom sql into your application if the traditional ActiveRecord methods won't get you what you need. When writing custom SQL in Rails, it is important to sanitize it, making sure there's no chance for an injection attack. Sometimes, however, you will have to interpolate Ruby variables into your SQL queries, but regular interpolation can be insecure. So what's the solution?

I have recently been working on an application with a Rails backend, that essentially matches musicians with each other based on similar interests, locational range, etc. When I was working on my Rails application recently, I had to write a long custom SQL statement. I wanted to make a method that could find users based on range, similar tags, and any filters like genres or instruments (in relation to the current user).

The query needed to be dynamic - the method containing the query took in arguments and those arguments would affect what the query would be looking for. Here is some pseudo code of the method I wanted to create.

Ok so we have our pseudo code. We know that we will have an array of ids of users to exclude in the query, an array of users that fit the range parameters, as well as an array of ids of users with instruments and genres that match the query. Here's where the sanitization comes in.

ActiveRecord has a sanitization method called sanitize_sql_array , that lets you pass an array into a SQL statement. It looks like: sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4]) . You pass an array into the method where the first index is the SQL query you want to write with the question mark placeholder, and the following indexes are variables you can pass in. With this method, any sql injections will be escaped, so you can safely pass variables to your query.

So for example, my users in range looks like this:

I am checking if there is range in the parameters of the method, and if there is, returning the sanitized sql that has executed the method that returns an array of user ids that are in range of a given radius. So that variable, range_query, can be accessed and put into the custom SQL query I would write later. One thing I should note is that you have to establish a connection with the ActiveRecord base to execute these methods. You may notice before the method is 'conn'. Before I use these methods I write: conn = ActiveRecord::Base so I can use conn as the base for the sanitization methods.

In the end, my sql query looked like this:

You can see how I interpolated variables that have already been sanitized (range_query and genre_instrument_query). I also interpolated the sanitize_sql_array method in a couple areas. So this is how you can safely interpolate in a custom SQL queries.

Top comments (0)

pic

Templates let you quickly answer FAQs or store snippets for re-use.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .

Hide child comments as well

For further actions, you may consider blocking this person and/or reporting abuse

anton_megaport profile image

How to open a web page by URL directly in Telegram.

Anton MegaPort - Apr 7

andersonsilva019 profile image

Eventual consistência em sistemas de banco de dados distribuídos

Anderson Silva - Apr 6

devluc profile image

Websites for Free Gatsby Templates

Devluc - Apr 7

devnla profile image

RESTful API vs GraphQL

Nay Lin Aung - Apr 7

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Rails 5 ActiveRecord Sanitized Order By

in Software on November 15, 2018 | Ruby Rails ActiveRecord

It may surprise you to find out that the default rails order function does not sanitize input. This can lead to potentially dangerous sql injections. Additionally, Rails 5 is starting to throw warnings when using order or sanitize_sql_for_order :

I don’t like users to be able to cause sql errors even with the worst input. I like clean logs. I went looking for someone who has solved this problem but didn’t find much. There was a decent sanitation function in a gist on github but it doesn’t work with joins. Here is a version of that function that operates cleanly when used on a joined query.

Add this file to config/initializers/sanitized_order.rb :

Use it like this and feel free to pass in user supplied data:

Beware though, a malicious user could use this to order by any column available in the model so you may need to add more protections to this depending on your use case.

Comments (3)

sanitize_sql_for_assignment rails 5

mcfoton Wednesday, May 1, 2019

Hi James, thanks for sharing :) One question though — what if I have the model name stated in the order clause directly, is there a way to check no only joins_values , but kind-of from-values ? Couldn’t find a method for that :( scope :ordered_by_city, ->(order) {sanitized_order("addresses.city", order)} Address.ordered_by_city('ASC') ->> RuntimeError (addresses unavailable in query)

sanitize_sql_for_assignment rails 5

James Kiefer In reply to mcfoton Wednesday, May 1, 2019

Oh good catch! Your example shouldn’t fail. I’ve revised the article and the function.

mcfoton In reply to mcfoton Sunday, May 12, 2019

Thanks! I’ve found some more edge cases. I’ll try to fix them and will update you a bit later. For now these are: When model is joined using a single form: joins(:state) it will not match against klass.pluralize.to_sym When join is done using syntax of joins(model1: :model2) it should unwrap the hash from joins_values P.S. I believe this is a valuable snippet we should polish so you can post it all over stackoverflow :)

Your comment has been submitted and will be published once it has been approved.

Your comment has not been submitted. Please go back and try again. Thank You!

If this error persists, please open an issue by clicking here .

Say something

Module: ActiveRecord::Sanitization::ClassMethods

Instance method summary.

Alias for #sanitize_sql_for_conditions .

Accepts an array of conditions.

Accepts an array, hash, or string of SQL conditions and sanitizes them into a valid SQL fragment for a SET clause.

Accepts an array or string of SQL conditions and sanitizes them into a valid SQL fragment for a WHERE clause.

Accepts an array, or string of SQL conditions and sanitizes them into a valid SQL fragment for an ORDER clause.

Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause.

Sanitizes a string so that it is safe to use within an SQL LIKE statement.

Instance Method Details

# sanitize_sql (condition), # sanitize_sql_array (ary).

Accepts an array of conditions. The array has each value sanitized and interpolated into the SQL statement.

# sanitize_sql_for_assignment (assignments, default_table_name = table_name)

# sanitize_sql_for_conditions (condition) also known as: #sanitize_sql, # sanitize_sql_for_order (condition), # sanitize_sql_hash_for_assignment (attrs, table), # sanitize_sql_like (string, escape_character = "\\").

Sanitizes a string so that it is safe to use within an SQL LIKE statement. This method uses escape_character to escape all occurrences of “", ”_“ and ”%“.

Search code, repositories, users, issues, pull requests...

Provide feedback.

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly.

To see all available qualifiers, see our documentation .

  • Notifications

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActiveRecord::Base.sanitize removed in 5.1 #28947

@niedfelj

niedfelj commented May 1, 2017

@rafaelfranca

rafaelfranca commented May 1, 2017

Sorry, something went wrong.

@rafaelfranca

kaspth commented May 1, 2017

  • 👍 1 reaction
  • 🎉 1 reaction
  • 😕 11 reactions

@maclover7

9mm commented Jun 23, 2017

  • 👍 3 reactions

@m1neral

m1neral commented Jun 23, 2017

  • 👍 23 reactions
  • 👎 2 reactions

@RoryO

thomasbalsloev commented Nov 22, 2018

  • 👍 2 reactions

@GUI

9mm commented Nov 22, 2018

Thomasbalsloev commented nov 23, 2018.

@ykessler

ykessler commented Dec 27, 2018 • edited

Thomasbalsloev commented jan 7, 2019.

@RowiDont

RowiDont commented Apr 4, 2019

@jackcasey

No branches or pull requests

@rafaelfranca

Apidock_header

sanitize_sql_for_order

Importance_1

  • 5.0.0.1 (0)
  • 6.1.3.1 (0)
  • 6.1.7.7 (0)
  • 7.1.3.2 (0)
  • What's this?

Related methods

  • Instance methods (20)

Importance_0_sm

Accepts an array, or string of SQL conditions and sanitizes them into a valid SQL fragment for an ORDER clause.

Go to Nodeta blog

Flowdock - Team Inbox With Chat

Flowdock is a collaboration tool for technical teams. Version control, project management, deployments and your group chat in one place.

IMAGES

  1. Rails Sanitize Sql? 5 Most Correct Answers

    sanitize_sql_for_assignment rails 5

  2. SQL : How to sanitize sql fragment in Rails

    sanitize_sql_for_assignment rails 5

  3. RailsでSQLインジェクションの対策:whereやsanitize_sqlメソッド

    sanitize_sql_for_assignment rails 5

  4. SQL : Best Practices for Sanitizing SQL inputs Using JavaScript?

    sanitize_sql_for_assignment rails 5

  5. SQL : How to sanitize database inputs in C or Objective-C?

    sanitize_sql_for_assignment rails 5

  6. SQL : Sanitize help on Raw sql

    sanitize_sql_for_assignment rails 5

VIDEO

  1. Curso Bases de Datos en MySQL

  2. Protecting from XSS with Sanitize

  3. SQL Learning Path

  4. Data Sanitization API

  5. Create a search bar in Rails with Mongoid

  6. SQL Learning Path

COMMENTS

  1. How to sanitize sql fragment in Rails

    Here a solution that works with Rails 4: In ActiveRecord::Sanitization::ClassMethods you have sanitize_sql_for_conditions and its two other aliases: sanitize_conditions and sanitize_sql.The three do literally the exact same thing. sanitize_sql_for_conditions. Accepts an array, hash, or string of SQL conditions and sanitizes them into a valid SQL fragment for a WHERE clause.

  2. ActiveRecord::Sanitization::ClassMethods

    Accepts an array of conditions. The array has each value sanitized and interpolated into the SQL statement. If using named bind variables in SQL statements where a colon is required verbatim use a backslash to escape.

  3. ruby

    Rails 5 SQL Injection. Ask Question Asked 7 years, 3 months ago. Modified 6 years, 6 months ago. Viewed 7k times 17 I've read about this for some time now on various SO threads, guides, etc... but all the answers are conflicting and contradictory. ... sanitize_sql_for_assignment; sanitize_sql_for_conditions; sanitize_sql_hash; sanitize_sql_hash ...

  4. ActiveRecord::Sanitization::ClassMethods

    sanitize_sql_for_assignment(assignments, default_table_name = table_name) Link Accepts an array, hash, or string of SQL conditions and sanitizes them into a valid SQL fragment for a SET clause.

  5. sanitize_sql_for_assignment (ActiveRecord::Sanitization::ClassMethods

    sanitize_sql_for_assignment(assignments, default_table_name = table_name) public Accepts an array, hash, or string of SQL conditions and sanitizes them into a valid SQL fragment for a SET clause.

  6. sanitize_sql_for_assignment (ActiveRecord::Base)

    ActiveRecord::Sanitization::ClassMethods#sanitize_sql_for_assignment sanitize_sql_for_assignment (assignments) protected Accepts an array, hash, or string of SQL conditions and sanitizes them into a valid SQL fragment for a SET clause.

  7. Sanitizing SQL in Rails/ActiveRecord

    Before I use these methods I write: conn = ActiveRecord::Base so I can use conn as the base for the sanitization methods. In the end, my sql query looked like this: SELECT u.*, COALESCE(matching_tag_counts.n, 0) AS similarity_score. FROM users AS u. LEFT OUTER JOIN (. SELECT user_id, COUNT(*) AS n.

  8. Sanitizing Complex SQL Queries in Rails like a Pro

    Customer.sanitize_sql_for_assignment([sql, id, name]) Here Customer can be any ActiveRecord class. Id and Name are bindings in SQL. This invocation will return sanitized SQL that could be readily used to get executed using exec_query and return hash for us. Why should we sanitize the query?

  9. Rails 5 ActiveRecord Sanitized Order By

    Rails 5 ActiveRecord Sanitized Order By - James Kiefer. It may surprise you to find out that the default rails order function does not sanitize input. This can lead to potentially dangerous sql injections. Additionally, Rails 5 is starting to throw warnings when using order or sanitize_sql_for_order:

  10. Module: ActiveRecord::Sanitization::ClassMethods

    Accepts an array of SQL conditions and sanitizes them into a valid SQL fragment for a WHERE clause. Accepts an array, or string of SQL conditions and sanitizes them into a valid SQL fragment for an ORDER clause. Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause. Sanitizes a string so that it is safe to use within an ...

  11. Module: ActiveRecord::Sanitization::ClassMethods

    #sanitize_sql_for_assignment(assignments, default_table_name = table_name) Accepts an array, hash, or string of SQL conditions and sanitizes them into a valid SQL fragment for a SET clause. # sanitize_sql_for_conditions (condition) (also: #sanitize_sql)

  12. Make .sanitize_sql_for_assignment public · Issue #29507 · rails/rails

    If it's advised in the docs, it should not be private. I believe it is a perfectly valid use case to execute raw SQL and to sanitize it first, so I don't see a reason to make it private. I would do this also for sanitize_sql_for_conditions and sanitize_sql_for_order. System configuration. Rails version: 5.0.3 Ruby version: 2.3.1

  13. ActiveRecord::Base.sanitize removed in 5.1 #28947

    If someone is trying to sanitize a string for use in raw sql, for the current thread processing the request, the connection should be the exact same between the quote call and the exec_query call. Probably best to use the methods linked by yKessler anyways, since they can do more than just sanitize a simple string: https://api.rubyonrails.org ...

  14. ActiveRecord::Sanitization::ClassMethods

    Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause. # => "`posts`.`status` = NULL, `posts`.`group_id` = 1". Sanitizes a string so that it is safe to use within an SQL LIKE statement. This method uses escape_character to escape all occurrences of "", "_" and "%".

  15. ActiveRecord::Sanitization::ClassMethods

    sanitize_sql_for_assignment(assignments, default_table_name = self.table_name) Link. Accepts an array, hash, or string of SQL conditions and sanitizes them into a valid SQL fragment for a SET clause. ... and will be removed in Rails 5.0 ") attrs = PredicateBuilder. resolve_column_aliases self, attrs attrs = expand_hash_conditions_for_aggregates ...

  16. sanitize_sql_for_assignment (ActiveRecord::Sanitization::ClassMethods

    Related methods. Instance methods (20) disallow_raw_sql! (>= v6.0.0) expand_hash_conditions_for_...

  17. sanitize_sql_for_assignment (ActiveRecord::Sanitization ...

    sanitize_sql_for_assignment(assignments, default_table_name = table_name) public Accepts an array, hash, or string of SQL conditions and sanitizes them into a valid SQL fragment for a SET clause.

  18. sanitize_sql_for_conditions (ActiveRecord::Sanitization ...

    Accepts an array or string of SQL conditions and sanitizes them into a valid SQL fragment for a WHERE clause. Register or log in to add new notes.

  19. sql

    In a Rails 3 model you used to be able to do: query = self.sanitize_sql_array(["SELECT MONTH(created) AS month, YEAR(created) AS year FROM orders WHERE created>=? AND created<=? GROUP BY month

  20. sanitize_sql_for_order (ActiveRecord::Sanitization::ClassMethods

    Ruby on Rails; Flowdock. method. sanitize_sql_for_order. v6.0.0 - Show latest stable - 0 notes - Class: ClassMethods. 1.0.0; 1.1.6; 1.2.6; 2.0.3; 2.1.0; 2.2.1; 2.3.2 ... sanitize_sql_for_assignment; sanitize_sql_for_conditions; sanitize_sql_for_order; sanitize_sql_hash (= v4.2.9) sanitize_sql_hash_for_assig... sanitize_sql_hash_for_condi ...