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

Allows admins to query barcodes with sql where clauses #362

Merged
merged 6 commits into from
Aug 18, 2021

Conversation

dhakim87
Copy link
Contributor

@dhakim87 dhakim87 commented Aug 5, 2021

This is the private api side of using jquery's querybuilder to let admin users pick barcode search criteria.

This side takes the where clause from the user as is, which is a huge red flag for sql injection. May be worth asking how George handled this on the public api side, as taking in the full json query object and parsing it into sql in python might be safer (but will require some extra libraries it looks like).

Depending on our threat model, this may or may not be an issue-
Queries are only allowed to be performed by admin users (and an adversary achieving admin access generally grants substantial access to the database anyway)
Transactions are rolled back, so an admin user shouldn't be able to cause lasting damage by mistake
Queries are limited to the where clause of specific tables (assuming they can't escape out, which I can't guarantee)
The only usage of the route comes from microsetta-interface where all user data is correctly escaped in the generation of the where clause.

@wasade
Copy link
Member

wasade commented Aug 10, 2021

Thanks! The public API doesn't use SQL behind the scenes. Is it possible to use psycopg2's literals or other constructs so we can rely on its SQL injection machinery?

@wasade
Copy link
Member

wasade commented Aug 10, 2021

...if you merge commits from master, it should resolve the dependency issue now

…a sql condition. We now convert the json rules to sql server side, restricting access. Note that while sql injection is prevented by escaping table names and condition parameters, we are still exposing a conditional read oracle. You may assume that anyone with access to this api (any administrator user) is given the equivalent of table level read access to the project_barcode, ag_kit_barcode and barcode_scans tables
@dhakim87
Copy link
Contributor Author

I've moved the conversion from QueryBuilder json to sql conditions server side using psycopg2. This removes an attack vector where a bad actor with administrator credentials passes up improperly escaped sql. These routes still expose a conditional query oracle against a few tables in our database by design. Think of this as giving full table level read access to administrator users.

Copy link
Member

@wasade wasade left a comment

Choose a reason for hiding this comment

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

Thanks @dhakim87, this looks incredibly useful and generalizable! Just a few comments

with self._transaction.cursor() as cur:
# Appending the sql_cond like this
# is extremely dangerous! This must ONLY
# be called with administrator privileges
Copy link
Member

Choose a reason for hiding this comment

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

...if psycopg2 provides a way to clean way to filter this then we should do that. Otherwise, we should consider testing the string for danger.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this comment is outdated, with the change to parse the querybuilder rule json, the sql_cond is now fully escaped.

'type': 'string',
'input': 'select',
'values': {
"Blood (skin prick)": "Blood (skin prick)",
Copy link
Member

Choose a reason for hiding this comment

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

...for a separate time, but it really sucks having these strings replicated through the codebase

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Worst part is, I thought I found them in another file, but it was a different list than was in the yaml.

)
self.assertListEqual(
params,
['bobby" or 1=1"\\; DROP TABLES;']
Copy link
Member

Choose a reason for hiding this comment

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

Is this asserting that the sql injection will work...?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hahaha, it asserts that the parameter list generated is the string specified, meaning the injection failed since it couldn't close the quotes to escape out.

You can try running the exact query this generates, it will tell you that "1"="1" or "name" isn't a valid column name, and prove that little bobby drop tables is fully escaped.

@wasade wasade merged commit 36182fb into master Aug 18, 2021
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