𝗗𝗼𝗻'𝘁 𝗣𝗮𝗿𝘀𝗲 𝗦𝗤𝗟 𝘁𝗼 𝗠𝗮𝗸𝗲 𝗮 𝗤𝘂𝗲𝗿𝘆 𝗥𝘂𝗻𝗻𝗲𝗿 𝗥𝗲𝗮𝗱-𝗢𝗻𝗹𝘆 (クエリランナーを読み取り専用にするためにSQLをパースしてはいけない)

SQL文字列内のキーワードをチェックすることでデータベースを保護しようとするのは、もうやめましょう。

SQLを実行するツールを構築する場合、読み取り専用モードが必要になります。誤ったUPDATEによってデータが削除されるのを防ぎたいはずです。その際、最初に思いつくのはDELETEやDROPといった単語をブロックすることかもしれません。

ですが、それはやってはいけません。

文字列のチェックは簡単に回避できてしまいます。ユーザーはWITH句を使ってDELETEを隠したり、コメントを使ってコマンドを隠したりできます。また、テーブルに書き込みを行う関数を呼び出すことも可能です。結局、いたちごっこの負け戦に陥ることになります。

セキュリティはデータベースに任せましょう。

Postgresには、このための組み込み機能があります。トランザクションを読み取り専用(read-only)として宣言できるのです。そうすれば、サーバーはあらゆる書き込みコマンドを拒否します。これにはCTE、関数、DDLも含まれます。

Pythonでこれを正しく実装する方法は以下の通りです:

このアプローチではSQLテキストを検査しません。クエリは書かれた通りにサーバーへ送られます。あなたはエンジンに対して、ルールを強制するように指示しているのです。

安全性には2つの要素が必要です:

  1. 書き込みからの保護:読み取り専用トランザクションを使用する。
  2. リソース乱用からの保護:タイムアウトと行制限を使用する。

読み取り専用のクエリであっても、巨大なJOINによってシステムをクラッシュさせる可能性があります。読み取り専用トランザクションは書き込みを停止させますが、大量のリソース消費を止めることはできません。アドホックなSQLを安全にするには、その両方が必要です。

SQLのパースはやめましょう。データベースにその役割を果たさせましょう。

Source: https://dev.to/hitoshi1964/dont-parse-sql-to-make-a-query-runner-read-only-b62