import pytest from galaxy.util import sqlite def test_query_allowed(): __assert_allowed("SELECT * from FOO") __assert_allowed("SELECT f.col1, f.col2 from FOO as f") __assert_allowed("SELECT f.col1, b.col2 from FOO as f inner join BAR as b on f.id = b.foo_id") __assert_not_allowed("UPDATE FOO SET foo=6") __assert_not_allowed("TRUNCATE FOO") def test_sqlite_exploits(): # This is not really testing any Galaxy code, just experimenting with ways # to attempt to exploit sqlite3 connections. # More info... # http://atta.cked.me/home/sqlite3injectioncheatsheet connection = sqlite.connect(":memory:") connection.execute("create TABLE FOO (foo1 text)") __assert_has_n_rows(connection, "select * from FOO", 0) __assert_query_errors(connection, "select * from FOOX", "no such table") # Make sure sqlite query cannot execute multiple statements __assert_query_errors( connection, "select * from FOO; select * from FOO", "You can only execute one statement at a time." ) # Make sure sqlite cannot select on PRAGMA results __assert_query_errors(connection, "select * from (PRAGMA database_list)", "no such table: PRAGMA") __assert_has_n_rows(connection, "select * from FOO where foo1 in (SELECT foo1 from FOO)", 0) # Ensure nested queries cannot modify database. __assert_query_errors(connection, "select * from FOO where foo1 in (INSERT INTO FOO VALUES ('bar')", "syntax error") # Should access to the schema be disallowed? # __assert_has_n_rows(connection, "select * from SQLITE_MASTER", 0) def __assert_has_n_rows(connection, query, n): count = 0 for _ in connection.cursor().execute(query): count += 1 assert count == n def __assert_query_errors(connection, query, match): with pytest.raises(Exception, match=match): connection.cursor().execute(query) def __assert_allowed(query): assert sqlite.is_read_only_query(query), f"Query [{query}] fails allowlist." def __assert_not_allowed(query): assert not sqlite.is_read_only_query(query), f"Query [{query}] incorrectly fails allowlist."