mirror of
https://github.com/getredash/redash.git
synced 2026-03-22 01:00:14 -04:00
* add SQLQuery class with tests for safe queries and non-safe tautology attacks * add test for union query injections * split .apply calls to newline * add tests for comment attacks * remove double underscore * extract complex children check to variable * inherit from object because I'm not a lamer Co-Authored-By: rauchy <omer@rauchy.net> * simplify cognitive complexity * check that additional columns are not injected * detect appended queries * inline .apply calls * move SQLQuery to it's own module * move SQLQuery tests to their own module * serialize SQLQuery instances * raise an exception when attempting to serialize an unsafe query * queries without parameters are safe * remove redundant parentheses * use cached properties * rename SQLInjectionException to SQLInjectionError * support multiple word params and param negations * refactor out methods that don't involve any state * don't cache text() * reduce cognitive complexity
95 lines
3.1 KiB
Python
95 lines
3.1 KiB
Python
from unittest import TestCase
|
|
|
|
from redash.utils.sql_query import SQLInjectionError, SQLQuery
|
|
|
|
|
|
class TestSQLQuery(TestCase):
|
|
def test_serializes(self):
|
|
query = SQLQuery("SELECT * FROM users WHERE userid='{{userid}}'").apply({
|
|
"userid": 22
|
|
})
|
|
|
|
self.assertEqual(query.text, "SELECT * FROM users WHERE userid='22'")
|
|
|
|
def test_raises_when_serializing_unsafe_queries(self):
|
|
query = SQLQuery("SELECT * FROM users WHERE userid={{userid}}").apply({
|
|
"userid": "22 OR 1==1"
|
|
})
|
|
|
|
self.assertRaises(SQLInjectionError, getattr, query, 'text')
|
|
|
|
def test_marks_queries_without_params_as_safe(self):
|
|
query = SQLQuery("SELECT * FROM users")
|
|
|
|
self.assertTrue(query.is_safe())
|
|
|
|
def test_marks_simple_queries_with_where_params_as_safe(self):
|
|
query = SQLQuery("SELECT * FROM users WHERE userid='{{userid}}'").apply({
|
|
"userid": 22
|
|
})
|
|
|
|
self.assertTrue(query.is_safe())
|
|
|
|
def test_marks_simple_queries_with_column_params_as_safe(self):
|
|
query = SQLQuery("SELECT {{this_column}} FROM users").apply({
|
|
"this_column": "username"
|
|
})
|
|
|
|
self.assertTrue(query.is_safe())
|
|
|
|
def test_marks_multiple_simple_queries_as_safe(self):
|
|
query = SQLQuery("SELECT * FROM users WHERE userid='{{userid}}' ; SELECT * FROM profiles").apply({
|
|
"userid": 22
|
|
})
|
|
|
|
self.assertTrue(query.is_safe())
|
|
|
|
def test_marks_tautologies_as_not_safe(self):
|
|
query = SQLQuery("SELECT * FROM users WHERE userid={{userid}}").apply({
|
|
"userid": "22 OR 1==1"
|
|
})
|
|
|
|
self.assertFalse(query.is_safe())
|
|
|
|
def test_marks_union_queries_as_not_safe(self):
|
|
query = SQLQuery("SELECT * FROM users WHERE userid={{userid}}").apply({
|
|
"userid": "22 UNION SELECT body, results, 1 FROM reports"
|
|
})
|
|
|
|
self.assertFalse(query.is_safe())
|
|
|
|
def test_marks_comment_attacks_as_not_safe(self):
|
|
query = SQLQuery("SELECT * FROM users WHERE username='{{username}}' AND password='{{password}}'").apply({
|
|
"username": "admin' --"
|
|
})
|
|
|
|
self.assertFalse(query.is_safe())
|
|
|
|
def test_marks_additional_columns_as_not_safe(self):
|
|
query = SQLQuery("SELECT {{this_column}} FROM users").apply({
|
|
"this_column": "username, password"
|
|
})
|
|
|
|
self.assertFalse(query.is_safe())
|
|
|
|
def test_marks_query_additions_as_not_safe(self):
|
|
query = SQLQuery("SELECT * FROM users ORDER BY {{this_column}}").apply({
|
|
"this_column": "id ; DROP TABLE midgets"
|
|
})
|
|
|
|
self.assertFalse(query.is_safe())
|
|
|
|
def test_marks_multiple_word_params_as_safe(self):
|
|
query = SQLQuery("SELECT {{why would you do this}} FROM users").apply({
|
|
"why would you do this": "shrug"
|
|
})
|
|
|
|
self.assertTrue(query.is_safe())
|
|
|
|
def test_marks_param_negations_as_safe(self):
|
|
query = SQLQuery("SELECT date_add(some_column, INTERVAL -{{days}} DAY) FROM events").apply({
|
|
"days": 7
|
|
})
|
|
|
|
self.assertTrue(query.is_safe())
|