Đừng Phân Tích Cú Pháp SQL Để Biến Trình Chạy Truy Vấn Thành Chế Độ Chỉ Đọc
Đừng cố gắng bảo mật cơ sở dữ liệu bằng cách kiểm tra các từ khóa trong chuỗi SQL.
Nếu bạn xây dựng một công cụ để chạy SQL, bạn sẽ muốn có chế độ chỉ đọc (read-only). Bạn muốn ngăn chặn một lệnh UPDATE vô tình làm mất dữ liệu. Ý nghĩ đầu tiên của bạn có thể là chặn các từ như DELETE hoặc DROP.
Đừng làm như vậy.
Việc kiểm tra chuỗi rất dễ bị vượt qua. Người dùng có thể sử dụng mệnh đề WITH để ẩn một lệnh DELETE. Họ có thể sử dụng chú thích (comments) để ẩn các câu lệnh. Họ có thể gọi một hàm thực hiện ghi vào bảng. Cuối cùng, bạn sẽ rơi vào một trò chơi "đập chuột" (whack-a-mole) đầy vô vọng.
Hãy để cơ sở dữ liệu tự xử lý vấn đề bảo mật.
Postgres có một tính năng tích hợp sẵn cho việc này. Bạn có thể khai báo một giao dịch (transaction) là chỉ đọc. Khi đó, máy chủ sẽ từ chối bất kỳ lệnh ghi nào. Điều này bao gồm cả CTEs, các hàm (functions) và DDL.
Dưới đây là cách triển khai chính xác trong Python:
- Sử dụng một giao dịch thực sự bằng cách đặt
autocommitthànhFalse. - Chạy
SET TRANSACTION READ ONLYnhư câu lệnh đầu tiên. - Thiết lập
statement_timeoutđể ngăn các truy vấn chạy lâu làm khóa hệ thống của bạn. - Sử dụng
rollback()ở cuối để giải phóng các khóa (locks) và bản chụp (snapshots).
Cách tiếp cận này không kiểm tra văn bản SQL. Truy vấn được gửi đến máy chủ chính xác như những gì đã viết. Bạn đang yêu cầu bộ máy (engine) thực thi quy tắc đó.
Sự an toàn đòi hỏi hai phần:
- Bảo vệ khỏi các lệnh ghi: Sử dụng các giao dịch chỉ đọc.
- Bảo vệ khỏi việc lạm dụng tài nguyên: Sử dụng timeout và giới hạn số dòng.
Một truy vấn chỉ đọc vẫn có thể làm sập hệ thống của bạn bằng một lệnh join khổng lồ. Một giao dịch chỉ đọc sẽ chặn các lệnh ghi, nhưng nó không ngăn chặn việc sử dụng tài nguyên quá mức. Bạn cần cả hai để đảm bảo các truy vấn SQL ad-hoc được an toàn.
Đừng phân tích cú pháp SQL nữa. Hãy để cơ sở dữ liệu làm công việc của nó.
Nguồn: https://dev.to/hitoshi1964/dont-parse-sql-to-make-a-query-runner-read-only-b62