MariaDB
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> MariaDB

Cách bảo vệ cơ sở dữ liệu MySQL hoặc MariaDB của bạn khỏi SQL Injection:Phần thứ hai

Trong phần đầu tiên của blog này, chúng tôi đã mô tả cách ProxySQL có thể được sử dụng để chặn các truy vấn đến được coi là nguy hiểm. Như bạn đã thấy trong blog đó, đạt được điều này rất dễ dàng. Tuy nhiên, đây không phải là một giải pháp đầy đủ. Bạn có thể cần thiết kế một thiết lập bảo mật chặt chẽ hơn nữa - bạn có thể muốn chặn tất cả các truy vấn và sau đó chỉ cho phép một số truy vấn được chọn đi qua. Có thể sử dụng ProxySQL để thực hiện điều đó. Hãy xem cách nó có thể được thực hiện.

Có hai cách để triển khai danh sách trắng trong ProxySQL. Đầu tiên, quy tắc lịch sử, sẽ là tạo quy tắc nhận tất cả sẽ chặn tất cả các truy vấn. Nó phải là quy tắc truy vấn cuối cùng trong chuỗi. Ví dụ bên dưới:

Chúng tôi đang khớp mọi chuỗi và tạo ra thông báo lỗi. Đây là quy tắc duy nhất tồn tại tại thời điểm này, nó ngăn không cho bất kỳ truy vấn nào được thực thi.

mysql> USE sbtest;

Database changed

mysql> SELECT * FROM sbtest1 LIMIT 10;

ERROR 1148 (42000): This query is not on the whitelist, you have to create a query rule before you'll be able to execute it.

mysql> SHOW TABLES FROM sbtest;

ERROR 1148 (42000): This query is not on the whitelist, you have to create a query rule before you'll be able to execute it.

mysql> SELECT 1;

ERROR 1148 (42000): This query is not on the whitelist, you have to create a query rule before you'll be able to execute it.

Như bạn thấy, chúng tôi không thể chạy bất kỳ truy vấn nào. Để ứng dụng của chúng tôi hoạt động, chúng tôi sẽ phải tạo các quy tắc truy vấn cho tất cả các truy vấn mà chúng tôi muốn cho phép thực thi. Nó có thể được thực hiện cho mỗi truy vấn, dựa trên thông báo hoặc mẫu. Bạn cũng có thể cho phép lưu lượng truy cập dựa trên các yếu tố khác:tên người dùng, máy chủ khách hàng, lược đồ. Hãy cho phép CHỌN vào một trong các bảng:

Bây giờ chúng ta có thể thực hiện các truy vấn trên bảng này, nhưng không thực thi trên bất kỳ bảng nào khác:

mysql> SELECT id, k FROM sbtest1 LIMIT 2;

+------+------+

| id   | k |

+------+------+

| 7615 | 1942 |

| 3355 | 2310 |

+------+------+

2 rows in set (0.01 sec)

mysql> SELECT id, k FROM sbtest2 LIMIT 2;

ERROR 1148 (42000): This query is not on the whitelist, you have to create a query rule before you'll be able to execute it.

Vấn đề với cách tiếp cận này là nó không được xử lý hiệu quả trong ProxySQL, do đó trong ProxySQL 2.0.9 đi kèm với cơ chế tường lửa mới bao gồm thuật toán mới, tập trung vào trường hợp sử dụng cụ thể này và hơn thế nữa có hiệu quả. Hãy xem chúng ta có thể sử dụng nó như thế nào.

Đầu tiên, chúng ta phải cài đặt ProxySQL 2.0.9. Bạn có thể tải xuống các gói theo cách thủ công từ https://github.com/sysown/proxysql/releases/tag/v2.0.9 hoặc bạn có thể thiết lập kho lưu trữ ProxySQL.

Sau khi hoàn tất, chúng ta có thể bắt đầu xem xét và cố gắng cấu hình nó để sử dụng tường lửa SQL.

Bản thân quá trình này khá dễ dàng. Trước hết, bạn phải thêm người dùng vào bảng mysql_firewall_whitelist_users. Nó chứa tất cả những người dùng nên bật tường lửa.

mysql> INSERT INTO mysql_firewall_whitelist_users (username, client_address, mode, comment) VALUES ('sbtest', '', 'DETECTING', '');

Query OK, 1 row affected (0.00 sec)

mysql> LOAD MYSQL FIREWALL TO RUNTIME;

Query OK, 0 rows affected (0.00 sec)

Trong truy vấn ở trên, chúng tôi đã thêm người dùng ‘sbtest’ vào danh sách người dùng nên bật tường lửa. Có thể nói rằng chỉ các kết nối từ một máy chủ nhất định mới được kiểm tra theo các quy tắc tường lửa. Bạn cũng có thể có ba chế độ:"TẮT", khi không sử dụng tường lửa, "PHÁT HIỆN", nơi các truy vấn không chính xác được ghi lại nhưng không bị chặn và "BẢO VỆ", nơi các truy vấn không được phép sẽ không được thực hiện.

Hãy bật tường lửa của chúng tôi:

mysql> SET mysql-firewall_whitelist_enabled=1;

Query OK, 1 row affected (0.00 sec)

mysql> LOAD MYSQL VARIABLES TO RUNTIME;

Query OK, 0 rows affected (0.00 sec)

Tường lửa ProxySQL dựa trên bản tóm tắt các truy vấn, nó không cho phép sử dụng các biểu thức chính quy. Cách tốt nhất để thu thập dữ liệu về những truy vấn nào nên được phép là sử dụng bảng stats.stats_mysql_query_digest, nơi bạn có thể thu thập các truy vấn và thông báo của chúng. Trên hết, ProxySQL 2.0.9 đi kèm với một bảng mới:history_mysql_query_digest, là một phần mở rộng liên tục cho bảng trong bộ nhớ đã đề cập trước đó. Bạn có thể định cấu hình ProxySQL để lưu trữ dữ liệu trên đĩa theo thời gian:

mysql> SET admin-stats_mysql_query_digest_to_disk=30;

Query OK, 1 row affected (0.00 sec)

Cứ 30 giây dữ liệu về các truy vấn sẽ được lưu trữ trên đĩa. Hãy chờ xem việc này sẽ đi đến đâu. Chúng tôi sẽ thực hiện một số truy vấn và sau đó kiểm tra kết quả của chúng:

mysql> SELECT schemaname, username, digest, digest_text FROM history_mysql_query_digest;

+------------+----------+--------------------+-----------------------------------+

| schemaname | username | digest             | digest_text |

+------------+----------+--------------------+-----------------------------------+

| sbtest     | sbtest | 0x76B6029DCBA02DCA | SELECT id, k FROM sbtest1 LIMIT ? |

| sbtest     | sbtest | 0x1C46AE529DD5A40E | SELECT ?                          |

| sbtest     | sbtest | 0xB9697893C9DF0E42 | SELECT id, k FROM sbtest2 LIMIT ? |

+------------+----------+--------------------+-----------------------------------+

3 rows in set (0.00 sec)

Khi chúng tôi đặt tường lửa ở chế độ 'DETECTING', chúng tôi cũng sẽ thấy các mục nhập trong nhật ký:

2020-02-14 09:52:12 Query_Processor.cpp:2071:process_mysql_query(): [WARNING] Firewall detected unknown query with digest 0xB9697893C9DF0E42 from user [email protected]

2020-02-14 09:52:17 Query_Processor.cpp:2071:process_mysql_query(): [WARNING] Firewall detected unknown query with digest 0x76B6029DCBA02DCA from user [email protected]

2020-02-14 09:52:20 Query_Processor.cpp:2071:process_mysql_query(): [WARNING] Firewall detected unknown query with digest 0x1C46AE529DD5A40E from user [email protected]

Bây giờ, nếu chúng ta muốn bắt đầu chặn các truy vấn, chúng ta nên cập nhật người dùng của mình và đặt chế độ thành 'PROTECTING'. Điều này sẽ chặn tất cả lưu lượng truy cập, vì vậy hãy bắt đầu bằng cách đưa các truy vấn vào danh sách trắng ở trên. Sau đó, chúng tôi sẽ bật chế độ "BẢO VỆ":

mysql> INSERT INTO mysql_firewall_whitelist_rules (active, username, client_address, schemaname, digest, comment) VALUES (1, 'sbtest', '', 'sbtest', '0x76B6029DCBA02DCA', ''), (1, 'sbtest', '', 'sbtest', '0xB9697893C9DF0E42', ''), (1, 'sbtest', '', 'sbtest', '0x1C46AE529DD5A40E', '');

Query OK, 3 rows affected (0.00 sec)

mysql> UPDATE mysql_firewall_whitelist_users SET mode='PROTECTING' WHERE username='sbtest' AND client_address='';

Query OK, 1 row affected (0.00 sec)

mysql> LOAD MYSQL FIREWALL TO RUNTIME;

Query OK, 0 rows affected (0.00 sec)

mysql> SAVE MYSQL FIREWALL TO DISK;

Query OK, 0 rows affected (0.08 sec)

Thế là xong. Bây giờ chúng ta có thể thực hiện các truy vấn trong danh sách trắng:

mysql> SELECT id, k FROM sbtest1 LIMIT 2;

+------+------+

| id   | k |

+------+------+

| 7615 | 1942 |

| 3355 | 2310 |

+------+------+

2 rows in set (0.00 sec)

Nhưng chúng tôi không thể thực thi những cái không có trong danh sách trắng:

mysql> SELECT id, k FROM sbtest3 LIMIT 2;

ERROR 1148 (42000): Firewall blocked this query

ProxySQL 2.0.9 đi kèm với một tính năng bảo mật thú vị khác. Nó đã nhúng libsqlinjection và bạn có thể cho phép phát hiện các SQL có thể chèn. Việc phát hiện dựa trên các thuật toán từ libsqlinjection. Tính năng này có thể được kích hoạt bằng cách chạy:

mysql> SET mysql-automatic_detect_sqli=1;

Query OK, 1 row affected (0.00 sec)

mysql> LOAD MYSQL VARIABLES TO RUNTIME;

Query OK, 0 rows affected (0.00 sec)

Nó hoạt động với tường lửa theo cách sau:

  • Nếu tường lửa được bật và người dùng đang ở chế độ BẢO VỆ, thì tính năng phát hiện chèn SQL sẽ không được sử dụng vì chỉ các truy vấn trong danh sách trắng mới có thể đi qua.
  • Nếu tường lửa được bật và người dùng đang ở chế độ PHÁT HIỆN, các truy vấn trong danh sách trắng sẽ không được kiểm tra để đưa vào SQL, tất cả các truy vấn khác sẽ được kiểm tra.
  • Nếu tường lửa được bật và người dùng đang ở chế độ ‘TẮT’, tất cả các truy vấn được coi là nằm trong danh sách trắng và không có truy vấn nào sẽ được kiểm tra để đưa vào SQL.
  • Nếu tường lửa bị tắt, tất cả các truy vấn sẽ được kiểm tra để tìm sự xâm nhập SQL.

Về cơ bản, nó chỉ được sử dụng khi tường lửa bị tắt hoặc cho người dùng ở chế độ 'DETECTING'. Thật không may, phát hiện SQL injection đi kèm với khá nhiều kết quả dương tính giả. Bạn có thể sử dụng bảng mysql_firewall_whitelist_sqli_fingerprints để đưa dấu vân tay vào danh sách trắng cho các truy vấn được phát hiện không chính xác. Hãy xem nó hoạt động như thế nào. Đầu tiên, hãy tắt tường lửa:

mysql> set mysql-firewall_whitelist_enabled=0;

Query OK, 1 row affected (0.00 sec)

mysql> LOAD MYSQL VARIABLES TO RUNTIME;

Query OK, 0 rows affected (0.00 sec)

Sau đó, hãy chạy một số truy vấn.

mysql> SELECT id, k FROM sbtest2 LIMIT 2;

ERROR 2013 (HY000): Lost connection to MySQL server during query

Thật vậy, có những kết quả dương tính giả. Trong nhật ký, chúng tôi có thể tìm thấy:

2020-02-14 10:11:19 MySQL_Session.cpp:3393:handler(): [ERROR] SQLinjection detected with fingerprint of 'EnknB' from client [email protected] . Query listed below:

SELECT id, k FROM sbtest2 LIMIT 2

Được rồi, hãy thêm tệp tham chiếu này vào bảng danh sách trắng:

mysql> INSERT INTO mysql_firewall_whitelist_sqli_fingerprints VALUES (1, 'EnknB');

Query OK, 1 row affected (0.00 sec)

mysql> LOAD MYSQL FIREWALL TO RUNTIME;

Query OK, 0 rows affected (0.00 sec)

Bây giờ cuối cùng chúng ta cũng có thể thực hiện truy vấn này:

mysql> SELECT id, k FROM sbtest2 LIMIT 2;

+------+------+

| id   | k |

+------+------+

|   84 | 2456 |

| 6006 | 2588 |

+------+------+

2 rows in set (0.01 sec)

Chúng tôi đã cố gắng chạy khối lượng công việc sysbench, điều này dẫn đến thêm hai tệp tham chiếu được thêm vào bảng danh sách trắng:

2020-02-14 10:15:55 MySQL_Session.cpp:3393:handler(): [ERROR] SQLinjection detected with fingerprint of 'Enknk' from client [email protected] . Query listed below:

SELECT c FROM sbtest21 WHERE id=49474

2020-02-14 10:16:02 MySQL_Session.cpp:3393:handler(): [ERROR] SQLinjection detected with fingerprint of 'Ef(n)' from client [email protected] . Query listed below:

SELECT SUM(k) FROM sbtest32 WHERE id BETWEEN 50053 AND 50152

Chúng tôi muốn xem liệu việc chèn SQL tự động này có thể bảo vệ chúng tôi trước người bạn tốt của chúng tôi, Booby Tables hay không.

mysql> CREATE TABLE school.students (id INT, name VARCHAR(40));

Query OK, 0 rows affected (0.07 sec)

mysql> INSERT INTO school.students VALUES (1, 'Robert');DROP TABLE students;--

Query OK, 1 row affected (0.01 sec)

Query OK, 0 rows affected (0.04 sec)

mysql> SHOW TABLES FROM school;

Empty set (0.01 sec)

Thật không may, không thực sự như vậy. Xin lưu ý rằng tính năng này dựa trên các thuật toán pháp y tự động, nó còn lâu mới hoàn hảo. Nó có thể là một lớp bảo vệ bổ sung nhưng sẽ không bao giờ có thể thay thế tường lửa được duy trì đúng cách được tạo bởi một người biết ứng dụng và các truy vấn của nó.

Chúng tôi hy vọng rằng sau khi đọc loạt bài ngắn gồm hai phần này, bạn sẽ hiểu rõ hơn về cách bạn có thể bảo vệ cơ sở dữ liệu của mình chống lại việc tiêm SQL và các nỗ lực độc hại (hoặc đơn giản là lỗi người dùng) bằng cách sử dụng ProxySQL. Nếu bạn có thêm ý tưởng, chúng tôi rất muốn nghe ý kiến ​​của bạn trong phần nhận xét.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. 2 cách trả về hàng chỉ chứa các ký tự không phải chữ và số trong MariaDB

  2. Chạy các truy vấn phân tích dữ liệu lớn bằng SQL và Presto

  3. Lập phiên bản dữ liệu tự động trong máy chủ MariaDB 10.3

  4. 2 cách để có được bộ ký tự có sẵn trong MariaDB

  5. Laravel:Khóa được chỉ định quá dài; độ dài khóa tối đa là 767 byte