Не используйте парсинг SQL для создания режима «только для чтения» в Query Runner
Перестаньте пытаться обезопасить базу данных, проверяя SQL-строки на наличие ключевых слов.
Если вы создаете инструмент для выполнения SQL-запросов, вам нужен режим «только для чтения». Вы хотите предотвратить случайный UPDATE, который может удалить ваши данные. Вашей первой мыслью может быть блокировка таких слов, как DELETE или DROP.
Не делайте этого.
Проверки строк легко обойти. Пользователь может использовать предложение WITH, чтобы скрыть DELETE. Можно использовать комментарии, чтобы спрятать команды. Можно вызвать функцию, которая записывает данные в таблицу. В итоге вы окажетесь в проигрышной игре в «прихлопни крота» (whack-a-mole).
Позвольте базе данных самой заниматься безопасностью.
В Postgres есть встроенная функция для этого. Вы можете объявить транзакцию только для чтения. После этого сервер будет отклонять любые команды записи. Это распространяется на CTE, функции и DDL.
Вот как правильно реализовать это на Python:
- Используйте настоящую транзакцию, установив
autocommitвFalse. - Выполните
SET TRANSACTION READ ONLYв качестве первой команды. - Установите
statement_timeout, чтобы предотвратить блокировку системы долгими запросами. - Используйте
rollback()в конце, чтобы освободить блокировки и снимки (snapshots).
Этот подход не проверяет текст SQL. Запрос отправляется на сервер именно в том виде, в котором он был написан. Вы просто приказываете движку базы данных соблюдать это правило.
Безопасность состоит из двух частей:
- Защита от записи: используйте транзакции только для чтения.
- Защита от злоупотребления ресурсами: используйте таймауты и лимиты строк.
Даже запрос «только для чтения» может обрушить вашу систему из-за огромного JOIN. Транзакция «только для чтения» останавливает запись, но она не предотвращает чрезмерное потребление ресурсов. Чтобы сделать ad-hoc SQL безопасным, вам нужны оба механизма.
Перестаньте парсить SQL. Попросите базу данных выполнять свою работу.
Источник: https://dev.to/hitoshi1964/dont-parse-sql-to-make-a-query-runner-read-only-b62