MariaDB
 sql >> Teknologi Basis Data >  >> RDS >> MariaDB

Cara Melindungi Database MySQL atau MariaDB Anda Dari SQL Injection:Bagian Kedua

Pada bagian pertama blog ini, kami menjelaskan bagaimana ProxySQL dapat digunakan untuk memblokir kueri masuk yang dianggap berbahaya. Seperti yang Anda lihat di blog itu, mencapai ini sangat mudah. Ini bukan solusi lengkap, meskipun. Anda mungkin perlu merancang penyiapan yang lebih aman lagi - Anda mungkin ingin memblokir semua kueri dan kemudian mengizinkan hanya beberapa kueri terpilih untuk dilewati. Dimungkinkan untuk menggunakan ProxySQL untuk mencapai itu. Mari kita lihat bagaimana hal itu dapat dilakukan.

Ada dua cara untuk menerapkan daftar putih di ProxySQL. Pertama, yang historis, adalah membuat aturan penampung-semua yang akan memblokir semua kueri. Itu harus menjadi aturan kueri terakhir dalam rantai. Contoh di bawah ini:

Kami mencocokkan setiap string dan menghasilkan pesan kesalahan. Ini adalah satu-satunya aturan yang ada saat ini, ini mencegah kueri apa pun untuk dieksekusi.

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.

Seperti yang Anda lihat, kami tidak dapat menjalankan kueri apa pun. Agar aplikasi kami berfungsi, kami harus membuat aturan kueri untuk semua kueri yang ingin kami izinkan untuk dieksekusi. Itu bisa dilakukan per kueri, berdasarkan intisari atau pola. Anda juga dapat mengizinkan lalu lintas berdasarkan faktor lain:nama pengguna, host klien, skema. Mari izinkan SELECT ke salah satu tabel:

Sekarang kita dapat menjalankan kueri pada tabel ini, tetapi tidak pada tabel lainnya:

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.

Masalah dengan pendekatan ini adalah bahwa hal itu tidak ditangani secara efisien di ProxySQL, oleh karena itu di ProxySQL 2.0.9 hadir dengan mekanisme firewall baru yang mencakup algoritma baru, berfokus pada kasus penggunaan khusus ini dan sebagainya efisien. Mari kita lihat bagaimana kita bisa menggunakannya.

Pertama, kita harus menginstal ProxySQL 2.0.9. Anda dapat mengunduh paket secara manual dari https://github.com/sysown/proxysql/releases/tag/v2.0.9 atau Anda dapat mengatur repositori ProxySQL.

Setelah ini selesai, kita dapat mulai memeriksanya dan mencoba mengonfigurasinya untuk menggunakan firewall SQL.

Prosesnya sendiri cukup mudah. Pertama-tama, Anda harus menambahkan pengguna ke tabel mysql_firewall_whitelist_users. Ini berisi semua pengguna yang firewallnya harus diaktifkan.

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)

Dalam kueri di atas, kami menambahkan pengguna 'sbtest' ke daftar pengguna yang seharusnya mengaktifkan firewall. Dimungkinkan untuk mengatakan bahwa hanya koneksi dari host tertentu yang diuji terhadap aturan firewall. Anda juga dapat memiliki tiga mode:'OFF', saat firewall tidak digunakan, 'DETECTING', di mana kueri yang salah dicatat tetapi tidak diblokir dan 'MELINDUNGI', jika kueri yang tidak diizinkan tidak akan dieksekusi.

Mari kita aktifkan firewall kita:

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)

Firewall proxySQL berdasarkan intisari kueri, tidak memungkinkan ekspresi reguler digunakan. Cara terbaik untuk mengumpulkan data tentang kueri mana yang boleh diizinkan adalah dengan menggunakan tabel stats.stats_mysql_query_digest, tempat Anda dapat mengumpulkan kueri dan intisarinya. Selain itu, ProxySQL 2.0.9 hadir dengan tabel baru:history_mysql_query_digest, yang merupakan ekstensi tetap ke tabel dalam memori yang disebutkan sebelumnya. Anda dapat mengonfigurasi ProxySQL untuk menyimpan data di disk dari waktu ke waktu:

mysql> SET admin-stats_mysql_query_digest_to_disk=30;

Query OK, 1 row affected (0.00 sec)

Setiap 30 detik data tentang kueri akan disimpan di disk. Mari kita lihat bagaimana kelanjutannya. Kami akan menjalankan beberapa kueri dan kemudian memeriksa intisarinya:

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)

Saat kita menyetel firewall ke mode 'MENDETEKSI', kita juga akan melihat entri di log:

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]

Sekarang, jika kita ingin mulai memblokir kueri, kita harus memperbarui pengguna kita dan menyetel mode ke 'MELINDUNGI'. Ini akan memblokir semua lalu lintas, jadi mari kita mulai dengan memasukkan kueri ke daftar putih di atas. Kemudian kita akan mengaktifkan mode 'MELINDUNGI':

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)

Itu dia. Sekarang kita dapat menjalankan kueri yang masuk daftar putih:

mysql> SELECT id, k FROM sbtest1 LIMIT 2;

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

| id   | k |

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

| 7615 | 1942 |

| 3355 | 2310 |

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

2 rows in set (0.00 sec)

Tetapi kami tidak dapat mengeksekusi yang tidak masuk daftar putih:

mysql> SELECT id, k FROM sbtest3 LIMIT 2;

ERROR 1148 (42000): Firewall blocked this query

ProxySQL 2.0.9 hadir dengan fitur keamanan menarik lainnya. Ini telah menyematkan libsqlinjection dan Anda dapat mengaktifkan deteksi kemungkinan injeksi SQL. Deteksi didasarkan pada algoritma dari libsqlinjection. Fitur ini dapat diaktifkan dengan menjalankan:

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)

Ini bekerja dengan firewall dengan cara berikut:

  • Jika firewall diaktifkan dan pengguna dalam mode MELINDUNGI, deteksi injeksi SQL tidak digunakan karena hanya kueri yang diizinkan secara eksplisit yang dapat melewatinya.
  • Jika firewall diaktifkan dan pengguna dalam mode DETEKSI, kueri yang masuk daftar putih tidak diuji untuk injeksi SQL, semua kueri lainnya akan diuji.
  • Jika firewall diaktifkan dan pengguna dalam mode 'OFF', semua kueri dianggap masuk daftar putih dan tidak ada yang akan diuji untuk injeksi SQL.
  • Jika firewall dinonaktifkan, semua kueri akan diuji untuk keamanan SQL.

Pada dasarnya, ini hanya digunakan jika firewall dinonaktifkan atau untuk pengguna dalam mode 'MENDETEKSI'. Deteksi injeksi SQL, sayangnya, hadir dengan cukup banyak kesalahan positif. Anda dapat menggunakan tabel mysql_firewall_whitelist_sqli_fingerprints untuk memasukkan sidik jari ke daftar putih untuk kueri yang terdeteksi secara tidak benar. Mari kita lihat cara kerjanya. Pertama, mari kita nonaktifkan firewall:

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)

Kalau begitu, mari kita jalankan beberapa kueri.

mysql> SELECT id, k FROM sbtest2 LIMIT 2;

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

Memang, ada positif palsu. Di log kita bisa menemukan:

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

Oke, mari tambahkan sidik jari ini ke tabel daftar putih:

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)

Sekarang akhirnya kita dapat menjalankan kueri ini:

mysql> SELECT id, k FROM sbtest2 LIMIT 2;

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

| id   | k |

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

|   84 | 2456 |

| 6006 | 2588 |

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

2 rows in set (0.01 sec)

Kami mencoba menjalankan beban kerja sysbench, ini menghasilkan dua sidik jari lagi yang ditambahkan ke tabel daftar putih:

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

Kami ingin melihat apakah injeksi SQL otomatis ini dapat melindungi kami dari teman baik kami, Booby Tables.

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)

Sayangnya, tidak juga. Harap diingat fitur ini didasarkan pada algoritma forensik otomatis, jauh dari sempurna. Ini mungkin datang sebagai lapisan pertahanan tambahan tetapi tidak akan pernah bisa menggantikan firewall yang dipelihara dengan baik yang dibuat oleh seseorang yang mengetahui aplikasi dan kuerinya.

Kami berharap setelah membaca seri dua bagian pendek ini, Anda memiliki pemahaman yang lebih baik tentang bagaimana Anda dapat melindungi database Anda dari injeksi SQL dan upaya jahat (atau sekadar kesalahan pengguna) menggunakan ProxySQL. Jika Anda memiliki lebih banyak ide, kami akan senang mendengar dari Anda di komentar.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana RTRIM_ORACLE() Bekerja di MariaDB

  2. Bagaimana SYSDATE() Bekerja di MariaDB

  3. Cara Menginstal dan Mengamankan MariaDB 10 di CentOS 7

  4. Memahami Indeks di MySQL:Bagian Ketiga

  5. Membangun Hot Standby di Amazon AWS Menggunakan MariaDB Cluster