Skip to content
New issue

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

Replace pg_search with activerecord query #351

Merged
merged 1 commit into from
Aug 14, 2015
Merged

Conversation

monfresh
Copy link
Member

Why:

We're only using the pg_search gem for the keyword search, and the query that it generates is not that complicated. Upgrading to the latest version of the pg_search gem breaks our tests. So, instead of having to rely on a third party, we can generate the same query ourselves using activerecord, and reduce our dependencies with the same stone.

How:

To figure out what the proper query was, I fired up the Rails console and ran Location.keyword('food'). That gave me the SQL query I needed, which I then converted to activerecord so that the result would return an ActiveRecord::Relation that can be chained with other scopes.

@@ -40,6 +26,17 @@ def status(param)
param == 'active' ? where(active: true) : where(active: false)
end

def keyword(k)
tsquery = <<-SQL
(to_tsquery('english', ''' ' || '#{k}' || ' ''' || ':*'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to introduce an SQL injection vector since #{k} is not escaped in any way. I know that tsquery is only interpolated into the SELECT and WHERE clause below, but I believe this is still exploitable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I believe I just need to replace '#{k}' with sanitize(k).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think sanitize is for HTML. One of the methods in here might help though: http://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I guess you're talking about this one: http://apidock.com/rails/ActiveRecord/Sanitization/ClassMethods/sanitize

Not sure why it's not listed on the previous page.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha! I was just gonna say the same thing. I wonder why. From what I can tell, all it does is place quotes around the query, which is the same as what I have now: '#{k}'.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of how this can be exploited so I can test it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just re-reading the Rails Security Guide a couple days ago and it has some good examples: http://guides.rubyonrails.org/security.html#sql-injection

It would take me a while to figure one out, but think you'd basically want to close the quoted string and the function call to to_tsquery, add in whatever other fields are needed plus a new FROM clause, then use -- to comment out the rest of the generated query.

The generated SQL is still going to be a SELECT clause, so an attacker probably couldn't destroy the DB with a DELETE, but I think it would be possible to construct a query that exposes the admins or users table.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why:

We're only using the pg_search gem for the keyword search, and the
query that it generates is not that complicated. Upgrading to the
latest version of the pg_search gem breaks our tests. So, instead of
having to rely on a third party, we can generate the same query
ourselves using activerecord, and reduce our dependencies with the
same stone.

How:

To figure out what the proper query was, I fired up the Rails console
and ran `Location.keyword('food')`. That gave me the SQL query I
needed, which I then converted to activerecord so that the result
would return an ActiveRecord::Relation that can be chained with other
scopes.
@monfresh
Copy link
Member Author

@md5 Check out the latest changes. I made the query even simpler thanks to help from my 18F colleagues, and sanitized the query in the order clause, and used a parameterized query in the where clause (which Postgres will automatically escape).

@md5
Copy link
Contributor

md5 commented Aug 14, 2015

LGTM

monfresh added a commit that referenced this pull request Aug 14, 2015
Replace pg_search with activerecord query
@monfresh monfresh merged commit 0c45228 into master Aug 14, 2015
@monfresh monfresh deleted the replace-pg-search branch August 14, 2015 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants