MySQL安全配置基線

SecIN發表於2022-05-16

實驗測試版本:mysql5.7.35

一、資料備份

描述

資料庫備份就是為了防止原資料丟失,保證資料的安全。當資料庫因為某些原因造成部分或者全部資料丟失後,備份檔案可以幫我們找回丟失的資料。因此,資料備份是很重要的工作。一般可採用本地備份和網路備份的形式,可採用MySQL本身自帶的mysqldump的方式和直接複製備份形式。

參考配置操作

定期對mysql進行異地備份。

二、賬戶安全

4.1 刪除預設資料庫及賬戶

描述

MySQL 初始化後會自動生成空使用者和 test 庫,以進行安裝時的測試,這些都是不需要的,有安全隱患,所以需要將他們全部刪除。

參考配置操作

在MySQL控制檯中,執行查詢資料庫:

mysql>use mysql;mysql>show databases;

wKg0C2JQBbqADFKuAAAp784HJDg212.png

然後將測試資料庫刪除。

注:此次實驗版本無test資料庫。

mysql> DROP DATABASE test;

4.2 刪除匿名賬戶和廢棄的賬戶

描述

依次檢查所列出的賬戶是否為必要賬戶,刪除無使用者或過期賬戶。

DROP USER語句用於刪除一個或多個MySQL賬戶。要使用DROP USER,必須擁有mysql資料庫的全域性CREATE USER許可權或DELETE許可權。賬戶名稱的使用者和主機部分與使用者表記錄的User和Host列值相對應。

參考配置操作

檢側操作:
mysql 檢視所有使用者的語句,輸入指令

select user();select user,host from mysql.user;

注:此次實驗版本無冗餘賬號。

使用DROP USER,您可以取消一個賬戶和其許可權,操作如下:

DROP USER user;

該語句可以刪除來自所有授權表的帳戶許可權記錄。紅色標識的無用賬戶都可以刪除。

wKg0C2JQBfWABTSLAAA7TQ7CYeI122.png

使用操作命令之後的結果

drop user ''@'mysql',''@'localhost','root'@'::1','root'@'mysql';

wKg0C2JQBgSAFCgHAACNmeKj2js247.png

4.3 預設賬戶(root)設定

描述

  • 安裝的 MySQL 的 root 使用者預設是空密碼,為了安全起見,需要把密碼修改為強密碼(包含數字、字母大小寫、特殊字元,長度大於 8 個字元)。
  • MySQL 預設許可權最高的使用者是 root,由於其許可權高,所以也是駭客最喜歡攻擊的使用者名稱,建議把 root 使用者名稱改名。

注:此次測試為5.7.35版本,初始化後已經為複雜密碼,非空密碼。

參考配置操作

改變root的密碼:

mysql>use mysql;mysql>update mysql.user set authentication_string=password('sehidk12e342') where user='root';#或mysql>update user set authentication_string=password('zkSzf_Sg&2021')where user = 'root';mysql>flush privileges;mysql>exit;Bye#上面的sehidk12e342為root使用者的密碼,請更改密碼為強密碼

系統mysql的管理員名稱是root,而一般情況下,資料庫管理員都沒進行修改,這一定程度上對系統使用者窮舉的惡意行為提供了便利,此時修改為複雜的使用者名稱,請不要在設定為admin或者administraror的形式,因為它們也在易猜的使用者字典中。

mysql> update user set user="newroot" where user="root"; //改成不易被猜測的使用者名稱mysql> flush privileges;

三、啟用日誌功能

描述

資料庫應配置日誌功能,啟動Mysql的日誌不僅可以為我們提供效能熱點的分析,還可以幫助我們加固Mysql資料庫的安全。

參考配置操作

mysql>show variables like '%log_%';檢視所有的log命令
mysql> show variables like '%log_%';
+--------------------------------------------+-------------------------------------------------+| Variable_name                              | Value                                           |
+--------------------------------------------+-------------------------------------------------+
| binlog_cache_size                          | 32768                                           || binlog_checksum                            | CRC32                                           |
| binlog_direct_non_transactional_updates    | OFF                                             || binlog_error_action                        | ABORT_SERVER                                    |
| binlog_format                              | ROW                                             || binlog_group_commit_sync_delay             | 0                                               |
| binlog_group_commit_sync_no_delay_count    | 0                                               || binlog_gtid_simple_recovery                | ON                                              |
| binlog_max_flush_queue_time                | 0                                               || binlog_order_commits                       | ON                                              |
| binlog_row_image                           | FULL                                            || binlog_rows_query_log_events               | OFF                                             |
| binlog_stmt_cache_size                     | 32768                                           || binlog_transaction_dependency_history_size | 25000                                           |
| binlog_transaction_dependency_tracking     | COMMIT_ORDER                                    || expire_logs_days                           | 0                                               |
| general_log_file                           | /usr/local/mysql/data/localhost.log             || innodb_flush_log_at_timeout                | 1                                               |
| innodb_flush_log_at_trx_commit             | 1                                               || innodb_log_buffer_size                     | 16777216                                        |
| innodb_log_checksums                       | ON                                              || innodb_log_compressed_pages                | ON                                              |
| innodb_log_file_size                       | 50331648                                        || innodb_log_files_in_group                  | 2                                               |
| innodb_log_group_home_dir                  | ./                                              || innodb_log_write_ahead_size                | 8192                                            |
| innodb_max_undo_log_size                   | 1073741824                                      || innodb_online_alter_log_max_size           | 134217728                                       |
| innodb_undo_log_truncate                   | OFF                                             || innodb_undo_logs                           | 128                                             |
| log_bin                                    | OFF                                             || log_bin_basename                           |                                                 |
| log_bin_index                              |                                                 || log_bin_trust_function_creators            | OFF                                             |
| log_bin_use_v1_row_events                  | OFF                                             || log_builtin_as_identified_by_password      | OFF                                             |
| log_error                                  | /var/log/mysqld.log                             || log_error_verbosity                        | 3                                               |
| log_output                                 | FILE                                            || log_queries_not_using_indexes              | OFF                                             |
| log_slave_updates                          | OFF                                             || log_slow_admin_statements                  | OFF                                             |
| log_slow_slave_statements                  | OFF                                             || log_statements_unsafe_for_binlog           | ON                                              |
| log_syslog                                 | OFF                                             || log_syslog_facility                        | daemon                                          |
| log_syslog_include_pid                     | ON                                              || log_syslog_tag                             |                                                 |
| log_throttle_queries_not_using_indexes     | 0                                               || log_timestamps                             | UTC                                             |
| log_warnings                               | 2                                               || max_binlog_cache_size                      | 18446744073709547520                            |
| max_binlog_size                            | 1073741824                                      || max_binlog_stmt_cache_size                 | 18446744073709547520                            |
| max_relay_log_size                         | 0                                               || relay_log_basename                         | /usr/local/mysql/data/localhost-relay-bin       |
| relay_log_index                            | /usr/local/mysql/data/localhost-relay-bin.index || relay_log_info_file                        | relay-log.info                                  |
| relay_log_info_repository                  | FILE                                            || relay_log_purge                            | ON                                              |
| relay_log_recovery                         | OFF                                             || relay_log_space_limit                      | 0                                               |
| slow_query_log_file                        | slow.log                                        || sql_log_bin                                | ON                                              |
| sql_log_off                                | OFF                                             || sync_relay_log_info                        | 10000                                           |
+--------------------------------------------+-------------------------------------------------+
66 rows in set (0.00 sec)
mysql>set global general_log_file=on;  //開啟常規日誌記錄。

mysql>show variables like 'general_log_file';檢視常規日誌開啟情況的log命令

+------------------+-------------------------------------+| Variable_name    | Value                               |
+------------------+-------------------------------------+| general_log_file | /usr/local/mysql/data/localhost.log |
+------------------+-------------------------------------+1 row in set (0.00 sec)

注:set global general_log_file=on; 如果使用該方法設定的日誌開啟,當mysql服務重啟後會失效,需要將以下兩條引數新增到/etc/my.cnf檔案中。

general_log_file = 1
slow_query_log_file = localhost.log

四、安全補丁

描述

確保資料庫版本為最新並修復已知的安全漏洞。攻擊者可能會利用已知的漏洞對MySQL伺服器進行攻擊。

參考配置操作

mysql> show variables where variable_name like 'version';
+---------------+--------+| Variable_name | Value  |
+---------------+--------+
| version       | 5.7.35 |+---------------+--------+1 row in set (0.00 sec)

顯示當前的資料庫版本,如果不是最新版本則安裝最新版本的補丁或升級到最新版本。

五、遠端訪問控制

5.1 禁用遠端訪問

描述

禁止網路連線,防止猜解密碼攻擊,溢位攻擊和嗅探攻擊。(僅限於應用和資料庫在同一臺主機)。

參考配置操作

1.如果資料庫不需遠端訪問,可以禁止遠端tcp/ip連線:

透過在mysqld伺服器中引數中新增 --skip-networking 啟動引數來使mysql不監聽任何TCP/IP連線,增加安全性。強迫MySQL僅監聽本機,方法是在my.cnf的 “[mysqld]” 部分增加下面一行:

bind-address=127.0.0.1

在命令列netstat -ant下看到,預設的3306埠是開啟的,此時開啟了mysqld的網路監聽,允許使用者遠端透過帳號密碼連線數本地據庫,預設情況是允許遠端連線資料的。為了禁止該功能,啟動skip-networking,不監聽sql的任何TCP/IP的連線,切斷遠端訪問的權利,保證安全性。假如確實需要遠端連線資料庫,至少修改預設的監聽埠,同時新增防火牆規則,只允許可信任的網路的mysql監聽埠的資料透過。

# vim /etc/my.cf將#skip-networking註釋去掉。#/usr/local/mysql/bin/mysqladmin -u root -p shutdown //停止資料庫#/usr/local/mysql/bin/mysqld_safe --user=mysql & //後臺用mysql使用者啟動mysql

5.2 只允許某個IP進行遠端訪問

描述

限制遠端訪問,只允許某個IP地址訪問資料庫(應用和資料庫不在同一臺主機)。

參考配置操作

檢查是否存在host值為‘%’的賬戶,如果存在,刪除該賬戶。

mysql> select user,host from user;  //查詢是否存在host值為‘%’的使用者。
+---------------+---------------+| user          | host          |
+---------------+---------------+
| newroot       | %             || webuser       | 192.168.200.1 |
| newroot       | localhost     |+---------------+---------------+3 rows in set (0.00 sec)

mysql> drop user newroot@'%';       //刪除使用者
mysql> flush privileges;            //重新整理快取

命令如下:

mysql>GRANT ALL PRIVILEGES ON *.* TO 'webuser'@'192.168.200.1' IDENTIFIED BY 'sehidk12e342';#sehidk12e342為密碼mysql>flush privileges;

六、許可權控制

6.1 禁止 MySQL 對本地檔案的讀取

描述

禁用”LOAD DATA LOCAL INFILE”命令,這有助於防止非授權使用者訪問本地檔案。在PHP應用程式中發現有新的SQL隱碼攻擊漏洞時,這樣做尤其重要。此外,在某些情況下,LOCAL INFILE命令可被用於訪問作業系統上的其它檔案(如/etc/passwd),若駭客讀取 /etc/passwd 檔案將非常危險。

參考配置操作

應使用下面的命令:

mysql> SELECT load_file("/etc/passwd");
mysql>load data local infile "/etc/passwd" into table teacher FIELDS TERMINATED BY '\n'; //讀取/etc/passwd並匯入到teacher表裡。
Query OK, 9 rows affected, 45 warnings (0.00 sec)Records: 9  Deleted: 0  Skipped: 0  Warnings: 45mysql> select * from teacher;  //查詢表teacher內所有資料,已經讀取到資料。
+-----------+----------+------------+------------+------------------+| teacherno | tname    | major      | prof       | department       |+-----------+----------+------------+------------+------------------+| games:    | ftp:x:14 | nobody:x:9 | systemd-ne | dbus:x:81:81:Sys || gluste    | saslauth | abrt:x:173 | setroubles | rtkit:x:172:172: || ntp:x:    | gdm:x:42 | gnome-init | sshd:x:74: | avahi:x:70:70:Av || polkit    | sssd:x:9 | libstorage | rpc:x:32:3 | colord:x:996:993 || postfi    | tcpdump: | webuser:x: | mysql:x:98 |                  || pulse:    | chrony:x | rpcuser:x: | nfsnobody: | unbound:x:991:98 || root:x    | bin:x:1: | daemon:x:2 | adm:x:3:4: | lp:x:4:7:lp:/var || sync:x    | shutdown | halt:x:7:0 | mail:x:8:1 | operator:x:11:0: || tss:x:    | usbmuxd: | geoclue:x: | radvd:x:75 | qemu:x:107:107:q |+-----------+----------+------------+------------+------------------+9 rows in set (0.00 sec)

開啟編輯/etc/my.cnf,新增local -infile=0。重新啟動MySQL服務。

再次測試:

mysql> load data local infile "/etc/passwd" into table teacher FIELDS TERMINATED BY '\n';
ERROR 1148 (42000): The used command is not allowed with this MySQL version
mysql>

6.2 資料庫目錄許可權控制

描述

預設的mysql是安裝在/usr/local/mysql,而對應的資料庫檔案在/usr/local/mysql/var目錄下,因此,必須保證該目錄不能讓未經授權的使用者訪問後把資料庫打包複製走了,所以要限制對該目錄的訪問。確保mysqld執行時,只使用對資料庫目錄具有讀或寫許可權的linux使用者來執行。

參考配置操作

# chown -R root  /usr/local/mysql/  //mysql主目錄給root# chown -R mysql.mysql /usr/local/mysql/var //確保資料庫目錄許可權所屬mysql使用者

6.3 普通使用者的資料庫最小特權

描述

有些應用程式是透過一個特定資料庫表的使用者名稱和口令連線到MySQL的,安全人員不應當給予這個使用者(普通使用者)完全的訪問權。
如果攻擊者獲得了這個擁有完全訪問權的使用者,他也就擁有了所有的資料庫。檢視一個使用者許可的方法是在MySQL控制檯中使用命令SHOW GRANT

參考配置操作

>SHOW GRANTS FOR 'newroot'@'localhost';//檢視newroot賬戶在本機授權訪問情況。為定義使用者的訪問權,使用GRANT命令。在下面的例子中,newroot僅能從test資料庫的user表中選擇:> GRANT SELECT ON test.user TO 'newroot'@'localhost';> FLUSH PRIVILEGES;newroot使用者就無法改變資料庫中這個表和其它表的任何資料。
如果你要從一個使用者移除訪問權,就應使用一個與GRANT命令類似的REVOKE命令:> REVOKE SELECT ON test.user FROM 'newroot'@'localhost';> FLUSH PRIVILEGES;
許可權許可權範圍給誰授權許可權範圍
grant all**ON **.to newroot授權newroot全庫許可權
grant selectON test.*to newroot授權newroot唐古拉資料庫檢視許可權
grant createON test.*to newroot授權newroot唐古拉資料庫新增許可權

授權並建立使用者,並指定密碼。

mysql>grant 許可權 on 許可權範圍  to 使用者 identified by '密碼';
例如:
mysql>grant all on test  to mysql identified by 'sehidk12e342';

回收許可權

revoke 許可權 on 範圍 from 使用者
例如:revoke all on mysql from root@'192.168.1.3';

6.4 刪除和禁用.mysql_history檔案

描述

我們使用過的 shell 命令,都會儲存在 ~/.bash_history 裡,透過 history 命令可以獲得當前使用者最近輸入的 1000 條命令。雖然前面我們登陸資料庫沒有直接使用密碼,但是以防萬一,還是建議清空 ~/.bash_history 檔案。

資料庫相關的shell操作命令都會分別記錄在.bash_history,如果這些檔案不慎被讀取,會導致資料庫密碼和資料庫結構等資訊洩露,而登陸資料庫後的操作將記錄在.mysql_history檔案中,如果使用update表資訊來修改資料庫使用者密碼的話,也會被讀取密碼,因此需要刪除這兩個檔案,同時在進行登陸或備份資料庫等與密碼相關操作時,應該使用-p引數加入提示輸入密碼後,隱式輸入密碼,建議將以上檔案置空。

參考配置操作

#cd ~    //開啟HOME資料夾# rm .bash_history .mysql_history  //刪除歷史記錄或者
# cat /dev/null .bash_history   //將shell記錄檔案置空# cat /dev/null .mysql_history  //將mysql記錄檔案置空

透過 mysql -uroot -p 登陸 MySQL 是一個良好的習慣。

6.5 禁止以root使用者許可權啟動mysqld系統程式

描述

以普通帳戶安全執行mysqld,禁止mysql以root帳號許可權執行,攻擊者可能透過mysql獲得系統root超級使用者許可權,完全控制系統。為資料庫建立獨立的linux中的mysql賬戶,該賬戶用來只用於管理和執行MySQL。

參考配置操作

檢查程式屬主和執行引數是否包含--user=mysql類似語句:

[root@localhost mysql]# ps -ef|grep mysqlroot       6870      1  0 19:42 pts/0    00:00:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/usr/local/mysql/data --pid-file=/tmp/mysqld/mysqld.pidmysql      7121   6870  5 19:42 pts/0    00:00:00 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/var/log/mysqld.log --pid-file=/tmp/mysqld/mysqld.pid --socket=/tmp/mysql.sock --port=3306root       7161   3033  0 19:42 pts/0    00:00:00 grep --color=auto mysql[root@localhost mysql]#

注:mysqld_safe是一個啟動指令碼,間接引用mysqld。在啟動mysqldsafe指令碼時,在啟動MySQL伺服器程式時,同時會啟動一個守護程式,作用是監控mysqld。

如mysqld服務掛了後,會立即重啟一個mysqld服務。

另外,mysqld_safe啟動方式也會把執行過程的報錯日誌和其它一些診斷資訊輸出到某一個檔案中,這樣方便我們排查解決問題。這個啟動方式是最常用的方式。

6.6 secure_file_priv引數應該為NULL

描述

secure_file_priv值不是NULL的時候可以透過資料庫對伺服器寫入shell,因此需要將該引數值設定為NULL。

secure_file_priv 為 /tmp 時,表示限制mysqld只能在/tmp目錄中執行匯入匯出,其他目錄不能執行。

secure_file_priv 沒有值時,表示不限制mysqld在任意目錄的匯入匯出。

檢視 secure_file_priv 的值,預設為NULL,表示限制不能匯入匯出。

參考配置操作

登入mysql後輸入以下命令檢視:

mysql> show variables like 'secure_file_priv';
+------------------+-------+| Variable_name    | Value |
+------------------+-------+
| secure_file_priv | NULL  |+------------------+-------+1 row in set (0.00 sec)

注:該實驗版本的mysql預設配置引數secure_file_priv值為NULL,不需要做修改。

七、修改mysql的埠

描述

  • 使用預設埠,會更容易被駭客在網路中發現資料庫,改成其他埠有助於隱藏資料庫,對mysql埠的修改可以從一定程度上防止埠掃描工具的掃描,防止被駭客入侵。
  • windows下可以修改配置檔案my.ini來實現,linux可以修改配置檔案my.cnf來實現。

參考配置操作

輸入以下命令檢視mysql預設埠號是不是3306:

[root@localhost mysql]#cat /etc/my.cnf |grep 'port'port=3306[root@localhost mysql]#

如果是3306則修改預設埠:

  1. 修改配置檔案vi /etc/my.cnf,
port=5618 (除3306以外的較大值埠)
  1. 重啟mysql服務
[root@localhost mysql]# service mysql restartShutting down MySQL.. SUCCESS! 
Starting MySQL. SUCCESS! 
[root@localhost mysql]#

相關文章