MySQL安全優化


一、數據庫相關

1、 MySQL版本的選擇

在正式生產環境中,建議使用5.6或以上系列的版本(5.7不建議,曾經用過這個版本,問題有點多)。

2、 運行用戶與端口的配置

2.1、確保MySQL運行用戶為一般用戶

確保mysql用戶登錄shell為nologin

[root@localhost ~]# usermod -s /sbin/nologin mysql

對MySQL運行用戶降權,以普通用戶身份運行MySQL

[root@localhost ~]# vim /usr/local/mysql/my.cnf
user = mysql
[root@localhost ~]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS! 
Starting MySQL. SUCCESS! 
[root@localhost ~]#

如果是用命令啟動的,則在參數后面加上--user=mysql即可。

注意存放目錄權限:

[root@localhost ~]# chown -R mysql.mysql /data/mysql/

按照以上操作后,mysql就會以用戶mysql身份來啟動mysqld,並且會以該用戶身份來接受連接。以上mysql用戶也可以改為其它用戶。(不改變safe_mysqld是必要的。)

2.2、修改默認端口

建議修改默認端口3306,改為其他的一些端口。

[root@localhost ~]# vim /usr/local/mysql/my.cnf
[mysqld]
 port = 3389
[root@localhost ~]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS! 
Starting MySQL. SUCCESS! 
[root@localhost ~]#

3、 開啟binlog

開啟mysql二進制日志,在誤刪除數據的情況下,可以通過二進制日志恢復到某個時間點

3.1、登錄MySQL查看bin-log狀態

登錄MySQL后,輸入show variables like '%log_bin%';查看到binlog日志為OFF關閉狀態;

image

3.2、開啟binlog

先quit退出MySQL

wpsF6F6.tmp

修改MySQL配置文件my.cnf,加入如下兩行

[root@localhost ~]# vim /usr/local/mysql/my.cnf
 server-id = 1
 log_bin = /data/mysql/mysql-bin

image

server-id標識着單個節點的id。在主從或者集群中會使用到,不能與其他節點相同。這里只有一台機,隨機設置一個數字就好了。

第二行指定bin-log的名字與存儲路徑。

3.3、重啟讓配置生效

[root@localhost ~]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS! 
Starting MySQL. SUCCESS! 
[root@localhost ~]#

查看數據庫日志目錄:

注意:每次服務器(數據庫)重啟,服務器會調用flush logs;,新創建一個binlog日志

由於我之前重啟過數據庫,因此這里有mysql-bin.000001到mysql-bin.000003這三個文件。這里你們看到的應該只有mysql-bin.000001和mysql-bin.index兩個文件

image

此時再次進入MySQL,查看binlog日志的狀態。顯示binlog日志為ON開啟狀態

image

到這里,binlog日志開啟成功。

 

4、 用戶認證和授權

4.1、刪除匿名賬號和空口令賬號

登錄MySQL,查看現在的賬號情況

image

一般我們在數據庫安裝之后就會刪除匿名賬戶如下:

mysql> delete from mysql.user where user='';

如上圖所示,User這一欄里面都有值,沒發現空的,所以沒有匿名賬戶。這一步略過。

發現Password欄有三行空的,所以本機有空口令賬號root。(危險)

我們為空口令賬戶設置密碼

mysql> update mysql.user set password=password('$MYSQL_PASSWORD') where User="root" and Host="localhost";
mysql> update mysql.user set password=password('$MYSQL_PASSWORD') where User="root" and Host="127.0.0.1";
mysql> update mysql.user set password=password('$MYSQL_PASSWORD') where User="root" and Host="::1";

設置完畢后,再查看如下:

wpsF6FB.tmp

此時已經沒有空口令和匿名賬戶了。

4.2、禁止root賬戶遠程訪問

Root權限太高,為了安全,一般我們禁止root賬戶從遠程訪問,root賬戶只允許從本地訪問。

4.2.1、賦予localhost的root賬戶最高權限(以后維護用)。

查看localhost的root權限:

wpsF6FC.tmp

一般,localhost的root默認具有所有的權限,如上圖(默認)。如果沒有,則按照以下命令賦予最高權限:

mysql> grant all privileges on *.* to root@localhost identified by 'password' with grant option;
mysql> flush priveleges;

4.2.2、禁止root從遠程訪問,將主機為%並且用戶為root行的刪掉。

mysql> delete from mysql.user where User='root' and Host='%';
Query OK, 1 row affected (0.00 sec)

或者

mysql> update user set host = "localhost" where user = "root" and host = "%";
mysql> flush privileges;

此時,你已經無法通過root賬戶進行遠程訪問數據庫了。

除了root賬戶外,其他賬戶也應該嚴格控制,盡量不要放開遠程訪問,如果必須的話,應嚴格控制權限。根據業務需要,配置其需要的最小權限。

如果不需要,應禁止遠程訪問

禁止網絡連接,防止猜解密碼攻擊、溢出攻擊、和嗅探攻擊。

注意: 僅限於應用和數據庫在同一台主機的情況。

如果數據庫不需要遠程訪問,可以禁止遠程 TCP/IP 連接,通過在 MySQL 服務器的啟動參數中添加--skip-networking參數使 MySQL 服務不監聽任何 TCP/IP 連接,增加安全性。

4.3、建立普通賬戶並授權

Root賬戶已經無法遠程進行訪問了,但是我們很多業務是需要遠程訪問的,所以為業務新建一個普通賬戶,並賦予他們需要的最小權限。權限最小化原則。

4.3.1、創建用戶

創建用戶有三種方式:

方式一:(create命令創建用戶)
mysql> create user 'test1'@'%' identified by '123';
Query OK, 0 rows affected (0.08 sec)

如果用戶已經存在會報錯。

mysql> create user 'test1'@'%' identified by '123';
ERROR 1396 (HY000): Operation CREATE USER failed for 'test1'@'%'

創建成功后,查看用戶如下:

image

方式二:(insert命令插入用戶,禁止使用此方式)
mysql> insert into mysql.user (Host,User,Password) Values('%','test2',PASSWORD('123'));
ERROR 1364 (HY000): Field 'ssl_cipher' doesn't have a default value

直接insert報錯,因為mysql默認禁止直接insert添加用戶。如果還是要改,可以修改配置文件:

[root@localhost doubles]# vim /usr/local/mysql/my.cnf
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

定位到上面這一行,這一行指定了mysql為嚴格模式,為了安全,嚴格模式是禁止使用insert形式創建mysql用戶的,如果堅持還是要用,把配置修改為:

sql_mode=NO_ENGINE_SUBSTITUTION

然后重啟服務

[root@localhost doubles]# /etc/init.d/mysqld restart

再次插入成功。

mysql> insert into mysql.user (Host,User,Password) Values('%','test2',PASSWORD('123'));
Query OK, 1 row affected, 3 warnings (0.00 sec)

改完配置再次插入成功。

image

方式三:(grant命令創建用戶)
mysql> grant select on *.* to 'test3'@'%' identified by '123';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

這種方式連同授權一起了。

image

查看權限發現test3已經授權成功,只有select權限,如下圖:

image

4.4、為新建用戶授權

遵循權限最小化原則。

4.4.1、查看用戶權限

方法一:

像上面一樣,用select查詢

mysql> select * from mysql.user where User='test3'\G;

方法二:

mysql> show grants for test3;

結果如下圖:

image

因為test3用戶時我們用grant命令創建的時候賦予了select權限,所以show grants for test3;時有select權限。

而test2與test1沒有授權,現在查看到是USAGE權限。

USAGE介紹:

1、連接(登陸)權限,建立一個用戶,就會自動授予其usage權限(默認授予)。

2、

mysql> grant usage on *.* to ‘p1′@’localhost’ identified by ‘123′;

3、該權限只能用於數據庫登陸,不能執行任何操作;且usage權限不能被回收,也即REVOKE用戶並不能刪除用戶。

4.4.2、授權

接下來為test2授權:

mysql> grant select,update on *.* to test2@'%';
Query OK, 0 rows affected (0.00 sec)

可以使用grant重復給用戶添加權限,進行權限疊加。

授權之后,一定要記得flush,權限才會生效:

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

不需要的權限可以用revoke回收:

mysql> revoke select on *.* from test2@'%';
Query OK, 0 rows affected (0.00 sec)

image

拓展:

之前我們有為localhost的root用戶授權,是這樣子:

mysql> grant all privileges on *.* to root@localhost identified by 'password' with grant option;

all privileges:除了root,不建議賦予普通用戶所有的權限。一般業務用戶所需要的也只是增刪改查,創建表等。根據需要賦予不同用戶不同權限。(管理員一定要做好權限控制。)

on *.*:表示在所有的庫和所有的表。這個一般是給管理員的。給業務用戶一般是要指定庫的,如:somedb.*。同樣是all privileges,基於管理員(.) 的所有權限跟基於業務庫(somedb.*) 上的所有權限也是不一樣的。

with grant option:表示讓用戶具備grant(其他用戶的)權限。(一般只給root)

4.5、MySQL權限列表

參考:https://www.cnblogs.com/tongxiaoda/p/7867796.html

Mysql支持的權限如下:

ALL或ALL PRIVILEGES  代表指定權限等級的所有權限。

ALTER   允許使用ALTER TABLE來改變表的結構,ALTER TABLE同時也需要CREATE和INSERT權限。重命名一個表需要對舊表具有ALTER和DROP權限,對新表具有CREATE和INSERT權限。

ALTER ROUTINE   允許改變和刪除存儲過程和函數

CREATE  允許創建新的數據庫和表

CREATE ROUTINE  允許創建存儲過程和包

CREATE TABLESPACE   允許創建、更改和刪除表空間和日志文件組

CREATE TEMPORARY TABLES 允許創建臨時表

CREATE USER 允許更改、創建、刪除、重命名用戶和收回所有權限

CREATE VIEW     允許創建視圖

DELETE  允許從數據庫的表中刪除行

DROP    允許刪除數據庫、表和視圖

EVENT   允許在事件調度里面創建、更改、刪除和查看事件

EXECUETE    允許執行存儲過程和包

FILE        允許在服務器的主機上通過LOAD DATA INFILE、SELECT ... INTO OUTFILE和LOAD_FILE()函數讀寫文件

GRANT OPTION    允許向其他用戶授予或移除權限

INDEX   允許創建和刪除索引

INSERT  允許向數據庫的表中插入行

LOCK TABLE  允許執行LOCK TABLES語句來鎖定表

PROCESS 允許顯示在服務器上執行的線程信息,即被會話所執行的語句信息。這個權限允許你執行SHOW PROCESSLIST和mysqladmin processlist命令來查看線程,同時這個權限也允許你執行SHOW ENGINE命令

PROXY   允許用戶冒充成為另外一個用戶

REFERENCES  允許創建外鍵

RELOAD  允許使用FLUSH語句

REPLICATION CLIENT  允許執行SHOW MASTER STATUS,SHOW SLAVE STATUS和SHOW BINARY LOGS命令

REPLICATION SLAVE   允許SLAVE服務器連接到當前服務器來作為他們的主服務器

SELECT  允許從數據庫中查詢表

SHOW DATABASES  允許賬戶執行SHOW DATABASE語句來查看數據庫。沒有這個權限的賬戶只能看到他們具有權限的數據庫。

SHOW VIEW   允許執行SHOW CREATE VIEW語句

SHUTDOWN    允許執行SHUTDOWN語句和mysqladmin shutdown已經mysql_shutdown() C API函數

SUPER   允許用戶執行CHANGE MASTER TO,KILL或mysqladmin kill命令來殺掉其他用戶的線程,允許執行PURGE BINARY LOGS命令,通過SET GLOBAL來設置系統參數,執行mysqladmin debug命令,開啟和關閉日志,即使read_only參數開啟也可以執行update語句,打開和關閉從服務器上面的復制,允許在連接數達到max_connections的情況下連接到服務器。

TRIGGER 允許操作觸發器

UPDATE  允許更新數據庫中的表

USAGE   代表沒有任何權限,只能登陸

mysql_privileges

5、 連接數設置

使用mysql的時候,經常會遇到MySQL: ERROR 1040: Too many connections這樣的問題,一種是訪問量確實很高,MySQL服務器抗不住,這個時候就要考慮增加從服務器分散讀壓力,另外一種情況是MySQL配置文件中max_connections值過小,這時,我們就需要調整當前最大連接數。

5.1、查看當前連接數

查看系統最大連接數設置:

mysql> show variables like '%max_connections%';

wpsF723.tmp

查看當前連接數情況:

mysql> status;

image

或者:

mysql> show status like '%thread%';

image

詳細查看當前連接數:

mysql> show full processlist;

5.2、修改最大連接數

5.2.1、命令行修改

mysql> set global max_connections=1000;

image

這種方式修改,只對當前環境有效,mysql重啟連接數就失效了。要想永久生效需要修改配置文件my.cnf。

5.2.1、修改配置文件

[root@localhost ~]# vim /usr/local/mysql/my.cnf
[mysqld]
...
max_connections=1000

image

重啟MySQL服務生效

[root@localhost ~]# /etc/init.d/mysql restart

修改連接數原則

使用show global status like 'Max_used_connections';查看當前MySQL響應的最大連接數,

mysql> show global status like 'Max_used_connections';

再用show variables like '%max_connections%';查看最大連接數。

wpsF728.tmp

對於mysql服務器最大連接數值的設置范圍比較理想的是:服務器響應的最大連接數值占服務器上限連接數值的比例值在10%以上,如果在10%以下,說明mysql服務器最大連接上限值設置過高。

Max_used_connections / max_connections * 100% = 151/2000 * 100% ≈ 7.5%

這里連接數設置的還是偏高了。

6、 MySQL備份

待補充。。。

7、 研發數據庫配置讀取規范

A、所有開發人員都不能知道正式服數據庫連接信息(包括數據庫連接地址,用戶名和密碼)。

B、開發人員讀取數據庫連接信息的時候,只能從配置文件中讀取。(測試環境一份,正式環境一份,代碼部署上線時,將正式環境的覆蓋測試環境的配置。)

C、配置文件可規定為某一種格式,如json格式。(可參考后端配置文件SrvNetIP.json)

{
        "DebugLog":1,
        "GmMode":1,
        "AutoAccout":0,
        "PlatformId":3,
        "ServerId":19,
        "GateSrv":
        {
                "Bind_Client_ipport" : "9000",
                "Bind_Srv_ipport" : "tcp://127.0.0.1:8000"
        },
        "GameSrv":
        {
                "Bind_Srv_ipport"   :"tcp://127.0.0.1:7000"
        },
        "WorldSrv":
        {
                "WorldSrvId":0,
                "Bind_Srv_ipport" : "tcp://127.0.0.1:6000"
        },
        "DBCache":
        {
                "Bind_Srv_ipport" : "tcp://127.0.0.1:5000",
                "DBLoginMySQL":
                {
                        "MySQL_ip" : "127.0.0.1",
                        "MySQL_port" : 3369,
                        "User" : "doubles",
                        "PassWd" : "123",
                        "DBName" : "doublesDB"
                }
        }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM