6. 安全性
在Mysql安装配置时要考虑安全性的影响,以下几点:
Ÿ 常规因素影响安全性
Ÿ 程序自身安全性
Ÿ 数据库内部的安全性,即,访问控制
Ÿ 网络安全性和系统安全性
Ÿ 数据文件的备份,日志文件和配置文件的安全性
6.1.2.5 mysql 4.1的应用程序的密码hash修改实现
6.3.7 插件式验证(Pluggable Authentication)
6.1 常规安全性问题
6.1.1安全性最佳实践
当运行mysql,有一下一些最佳实践:
1.静止用户访问mysql数据库上面的表
2.学习权限是如何工作的。不要授予过多的权限
checklist:测试mysql –uroot 连接,使用show grant查看被赋予了什么权限
3.不要在数据库中存明文密码
4.不要从字典里面选密码
5.安装防火墙
6.不能信任任何应用写入的数据,应该通过防御编程技术写入(defensive programming techniques)
7.学会使用tcpdump和strings工具截取tcp中的数据
6.1.2 保持密码安全性
6.1.2.1终端用户密码安全性最佳实践
1.使用mysql_config_editor工具,把认证数据写入到加密的.mylogin.cnf文件。
2.使用-ppassword或者—password=password会暴露密码明文
3.使用 -p,--password不指定密码,交互方式数据密码,避免密码明文暴露
4.如果密码明文方式在配置文件中,记得修改linux权限不让其他人访问。
5.把密码存放在环境变量 MYSQL_PWD,不推荐的访问,会验证影响安全。
在linux中,mysql客户端会记录命令在.mysql_history,create user,grant,set password的时候会写入到文件,为了安全性最好限制访问模式。
6.1.2.2 密码管理方法
1.不能让非管理员用户访问mysql.user表。
2.使用密码过期强制用户重设密码
3.使用validate_password插件强化密码策略
6.1.2.3 密码和日志
使用语句 create user,grant,set password或者调用了password函数,密码都是明文的,如果被记录,那么可能会被其他任何能够访问日志文件的人看到。
从mysql 5.6.3之后就不会以下语句,日志文件上出现明文(mariadb 10.0也不会显示明文):
CREATE USER ... IDENTIFIED BY ...
GRANT ... IDENTIFIED BY ...
SET PASSWORD ...
SLAVE START ... PASSWORD = ... (as of 5.6.4)
CREATE SERVER ... OPTIONS(... PASSWORD ...) (as of 5.6.9)
ALTER SERVER ... OPTIONS(... PASSWORD ...) (as of 5.6.9)
语句中的密码不会出现在,general query log,slow query log,binary log。general query log的password 重写可以使用—log-raw选项来限制。(使用mariadb 10.0测试无效)。
审计日志的文本是不加密的,所以不能让其他用户访问。
为了尽量避免日志内容保留,应该不能让系统和数据库管理员之外的用户访问日志文件。
复制slave在master info repository中保存了复制master的密码,会存在一个文件或者一个表中。要保证repository只能被数据库管理员读取。
6.1.2.4 Mysql中的密码hash
mysql的用户存放在mysql.user下,每个账号都有一个密码,密码是以hash值存放的。
mysql,在client和server交互的2个阶段用到密码:
1.client连接会把密码的hash,然后和user表的密码进行匹配
2.在登陆之后,可以修改密码。
原先的hash方法(4.1版本之前)会产生16字节的字符串。4.1版本之后的hash方法产生41字节的字符串并且密码以*号开头。
使用old_password()就是使用老的hash方法。当old_password变量为1是,password函数产生的结果16字节长度。
6.1.2.5 mysql 4.1的应用程序的密码hash修改实现
略
6.1.2.6 密码验证插件
validate_password(5.6.6之后),用来测试密码的安全性。这个插件有2个功能:
1.检查密码明文的密码策略
2.通过长度看密码强壮性。
如果使用密码明文,那么就会对密码进行验证,如果直接用hash值,那么就不验证。
密码验证插件安装方法:
1.使用配置文件
[mysqld]
plugin-load=validate_password.so
2.使用instal plugin命令,使用后会在mysql.plugins表中加入记录,下次启动会自动加载。
mysql> INSTALL PLUGIN validate_password SONAME 'validate_password.so';
validate-password可以用来控制服务启动的时候加载插件,如果值是FORCE或者FORCE_PLUS_PERMANENT,如果插件初始化失败,那么服务启动就失败。
6.1.3 防止Mysql被攻击
mysql在传输的时候密码不是明文传输的,但是其他信息都是明文,可能会被其他人读取,如果是和非信任网络的交互,可以使用ssl加密连接。
有以下几点可以让mysql系统更加安全:
1.每个mysql用户都要有密码
2.只有mysqld的启动用户有访问数据库文件夹的权限
3.不要用root用户启动mysql服务。这样每个连接都有服务器上的root权限,十分危险。
4.不要授予非管理员用户FILE权限
5.不要授予非管理员用户PROCESS和SUPER权限
6.不允许使用symlink到表。
7.存储过程和函数要在安全指导写编写,Section 20.6, “Access Control for Stored Programs and Views”.
8.在权限表中,如果对DNS不信任,那么就使用ip地址
9.如果要限制一个账号的最大连接数,可以使用max_user_connections变量。
6.1.4 安全相关的mysqld选项和变量
Name |
Cmd-Line |
Option file |
System Var |
Status Var |
Var Scope |
Dynamic |
Yes |
Yes |
|
|
|
|
|
|
|
Yes |
|
Global |
Yes |
|
Yes |
Yes |
|
|
|
|
|
Yes |
Yes |
|
|
|
|
|
|
|
Yes |
|
Global |
Yes |
|
|
|
Yes |
|
Both |
Yes |
|
Yes |
Yes |
|
|
|
|
|
Yes |
Yes |
|
|
Global |
Yes |
|
- Variable: secure_auth |
|
|
Yes |
|
Global |
Yes |
Yes |
Yes |
|
|
Global |
No |
|
- Variable: secure_file_priv |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
|
|
|
Yes |
Yes |
|
|
Global |
No |
|
- Variable: skip_name_resolve |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
Global |
No |
|
- Variable: skip_networking |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
Global |
No |
|
- Variable: skip_show_database |
|
|
Yes |
|
Global |
No |
6.1.5 使用常规用户启动mysql
修改mysqld启动用户步骤:
1.关闭mysql服务
2.修改数据库文件夹和文件总的读写权限,可以让启动用户读写数据库文件和文件夹
shell> chown -R user_name /path/to/mysql/datadir
3.使用—user=user_name或者在配置文件的user=user_name来指定启动账号,并启动服务。
6.1.6 LOAD DATA LOCAL安全问题
load data可以加载服务器上的文件,load data local可以加载client host的文件。
load data local有2个潜在安全性问题:
1.把client host文件传输到server host。那么server host要有权限,这样会造成server host可以访问任何 client user有权限可以访问的文件。
2.在web环境,用户连接到web服务,一个用户使用load data local就可以读取web服务进程可以读取的任何文件。
为了解决这些问题,在mysql 3.29做了处理:
1.binary版本,增加了-DENABLED_LOCAL_INFILE,默认为1,可以使用 local。
2.如果通过源代码编译没有加-DENABLED_LOCAL_INFILE=1那么就不能使用除非显示的使用了,mysql_options(... MYSQL_OPT_LOCAL_INFILE, 0)
.
3.可以通过配置—local-infile=0来限制load data local语句的使用。
4.mysql 客户端也可以设置—local-infile来禁用和启用load data local
5.如果是perl脚本或者其他程序,可以通过配置[client]的配置文件
6.如果load data local被禁用,使用的时候会报错:
ERROR 1148: The used command is not allowed with this MySQL version
6.1.7客户端程序安全性
具体看:
http://dev.mysql.com/doc/refman/5.6/en/secure-client-programming.html
6.2 mysql访问权限系统
mysql权限系统主要有2个功能:
1.给验证用户权限
2.给你匿名用户权限
权限系统中不能做的事:
· You cannot explicitly specify that a given user should be denied access. That is, you cannot explicitly match a user and then refuse the connection.
· You cannot specify that a user has privileges to create or drop tables in a database but not to create or drop the database itself.
· A password applies globally to an account. You cannot associate a password with a specific object such as a database, table, or routine.
mysql的权限信息都是存放在mysql数据库中,当服务启动的时候,把数据加载到内存,然后之后处理都是在内存层面。
mysql的权限系统保证了,所有用户只能操作被允许的行为。mysql是通过用户的identity来确定用户权限的identity=username@host。
mysql的访问控制分为2个阶段:
1.验证用户,连接
2.如果连接,然后通过检查用户权限来判断能否执行。
如果一个用户在连接状态,并且修改了这个用户的权限,那么这个用户的修改不会再下一个语句马上体现。
6.2.1 mysql提供的权限
mysql提供了应用在不同上下文和级别的权限:
1.实例级别,可以管理mysql server的管理。
2.数据库级别权限,应用于数据库和数据库里面的对象。
3.对象级别的权限,表,索引,视图,存储过程,函数。
账号的权限记录在mysql中的user,db,tables_priv,columns_priv,procs_priv。
以下表显示了,可以grant,revoke语句权限:
Privilege |
Column |
Context |
Create_priv |
databases, tables, or indexes |
|
Drop_priv |
databases, tables, or views |
|
Grant_priv |
databases, tables, or stored routines |
|
Lock_tables_priv |
databases |
|
References_priv |
databases or tables |
|
Event_priv |
databases |
|
Alter_priv |
tables |
|
Delete_priv |
tables |
|
Index_priv |
tables |
|
Insert_priv |
tables or columns |
|
Select_priv |
tables or columns |
|
Update_priv |
tables or columns |
|
Create_tmp_table_priv |
tables |
|
Trigger_priv |
tables |
|
Create_view_priv |
views |
|
Show_view_priv |
views |
|
Alter_routine_priv |
stored routines |
|
Create_routine_priv |
stored routines |
|
Execute_priv |
stored routines |
|
File_priv |
file access on server host |
|
Create_tablespace_priv |
server administration |
|
Create_user_priv |
server administration |
|
Process_priv |
server administration |
|
see proxies_priv table |
server administration |
|
Reload_priv |
server administration |
|
Repl_client_priv |
server administration |
|
Repl_slave_priv |
server administration |
|
Show_db_priv |
server administration |
|
Shutdown_priv |
server administration |
|
Super_priv |
server administration |
|
|
server administration |
|
|
server administration |
6.2.2 权限系统权限表
通常操作权限表是通过,grant,revoke来间接操作的。
mysql的表中一下表包含权限信息:
user:包含了用户账号,全局权限和其他权限列
db:数据库级别权限
host:mysql5.6.7之后就不存在,mariadb10.0也不存在
tables_priv:表级权限
columns_priv:列级权限
procs_priv:存储过程和函数权限
proxies_priv:代理用户权限
每个权限表包含适用范围列和权限列:
1.适用范围列决定了权限适用范围。
2.权限列表明了被授予的权限。
服务会在以下方式使用权限表:
1.user表的范围列决定了是拒绝或者允许连接。对于可连接的用户,在users表的权限都是全局权限,可以应用到所有数据库。
2.db表范围列确定了用户可以确定了从哪来的连接可以访问哪些数据库
3.tables_priv和columns_priv表和db表类似,但是粒度更加小,应用在表级和列级。
4.procs_priv应用在存储过程和函数的权限
5.proxies_priv表说明用户可以代理其他用户
具体权限表的表接口可以看:
http://dev.mysql.com/doc/refman/5.6/en/grant-table-structure.html
6.2.3 指定帐号(Account)名
帐号名规则:
1.帐号名规则是user_name@host_name
2.若指定一个用户名,就相当于’user_name’@’%’
3.如果不用引号合法,可以不用引号
4.用户名可以使用单引号,双引号,或者(`)
5.引号的添加方法不是’user_name@%’,是’user_name’@’%’
6.使用current_user或者current_user()获取当前用户名和host。
host是帐号的一部分可以有很多方式和通配符:
1.host可以指定hostname或者ip地址(ipv4,ipv6)。
2.你可以使用’%’或者’’替换host或者ip地址。
3.也可以使用host_ip/netmask格式代替host_name。
6.2.4 访问控制,阶段1:连接验证
当用户连接到mysql,通过了identity认证,则进入阶段2。
identity由2部分组成:
1.客户端host名
2.mysql用户名
identity的验证需要用到user表的3个字段,host,user,password。
如果user列不是空的,只能准确的匹配,如果user列是空的,可以匹配任意用户。若user表中的一行匹配了一个空用户名的用户,那么这个用户就被认为是匿名用户,不是指定用户名的用户。
password列如果为空的,并不意味着通配,而是空密码。如果plugin认证可以使用密码也可以不使用密码。如果password不是为空的,那么说明登陆的时候需要密码验证。
当连接的时候有多个可以匹配,就用以下方法:
1.不管什么时候服务读取user表到内存,会对行排序
2.当一个客户端视图连接,服务会通过排序的顺序匹配
3.服务会使用第一个匹配的username和hostname
排序,越准确的排在越前面。
如:
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| % | root | ...
| % | jeffrey | ...
| localhost | root | ...
| localhost | | ...
+-----------+----------+-
排序后:
+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| localhost | root | ...
| localhost | | ...
| % | jeffrey | ...
| % | root | ...
+-----------+----------+-
如果连接了,但是不是自己要的帐号,可以使用current_user()查看匹配的用户。
6.2.5 访问控制,阶段2:请求验证
连接之后,服务进入第二阶段,当客户端请求,服务就会去检查是否有权限来执行这个请求。权限可以通过表,user,db,tables_priv,columns_priv,procs_priv检查。
user表的权限是全局的适用于所有数据库。
在db表中:
1.空的用户名表示匿名用户,非空的表示指定用户
2.通配符和’’可以用在host和db列
3.’%’或者空的host表示任意host
4.’%’或者空的db表示任意数据库
db表通过host,db,user排序。
对于tables_priv,columns_priv,procs_priv:
1.host列可以有通配符
2.‘%‘或者空host表示任意host
3.db,table_name,column_name,routine_name列不能包含通配符或者空。
这几个表也是根据host,db,user排序。
对于数据库相关的请求,先看用户全局user表,若没有就查db表的权限。server查看db表,同难过host,db,user列进行匹配。
在确定指定数据库的权限,服务把权限添加到全局权限中,如果满足了就执行,如果不满足服务检查用户表和列的权限(tables_priv,columns_priv)把这些添加到用户权限,根据结果来确定是否执行。
权限的计算类似于这样:
global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges
OR routine privileges
但是如果出现一个请求需要多个权限的情况下,就不是这样。
6.2.6 权限修改生效时间
mysql启动会读取grant表到内存,这个时候才生效。
如果使用grant,revoke,setpassword,rename user间接的修改权限,服务会注意到时修改权限并会马上加载到内存。
若使用dml修改权限表,需要手动加载后才能生效。重新加载的方法:
1.flush privileges语句
2.mysqladmin flush-privilege
3.mysqladmin reload
权限生效之后会对每个存在的客户端影响:
1.表或者列权限修改,会影响客户端下一个请求
2.数据库权限修改会影响下一个use db_name语句
3.全局权限修改会影响下一个连接
如果在启动服务的时候使用—skip-grant-tables选线,不会读取权限表,不会对权限进行认证,可以随意访问数据。
6.2.7 访问拒绝的例子
略
具体可以看:http://dev.mysql.com/doc/refman/5.6/en/access-denied.html
6.3 MySQL用户帐号管理
6.3.1用户名和密码
mysql的帐号保存在user表中,帐号由用户名和host组成。
Ÿ 用户名,只用来做mysql验证。
Ÿ mysql用户名最常不能超过16个字节
Ÿ 服务使用存储在mysql.user的密码来验证客户端使用,mysql原生认证,如果指明了验证插件,那么由插件决定是否使用密码
Ÿ mysql的原生验证有自己的加密算法
Ÿ 若使用的用户密码有非ascii的字符,那么就要设置字符集,mysql客户端可以使用—default-character-set来修改字符集。
6.3.2 增加用户帐号
增加新的帐号由2种方式:
1.使用create user,grant,间接操作权限表
2.直接使用dml语句,直接操作权限表,当然需要flush privileges
mysql> CREATE USER 'francis'@'localhost' IDENTIFIED BY 'frank';
6.3.3 删除用户帐号
使用drop user语句来删除帐号
mysql> DROP USER 'francis'@'localhost'
6.3.4 设置帐号的资源限制
说是资源限制,无非就是限制每个账号的连接数。使用max_user_connections来限制。
在mysql5.6之后还可以对每个用户做某些限制,mariadb 10.0也有这个功能:
1.限制每小时的查询量
2.限制每小时的update量
3.限制每小时的连接次数
4.限制一个帐号并发的连接个数
以上4个限制,是通过grant语句限制的,使用help grant查看。
mysql> CREATE USER 'francis'@'localhost' IDENTIFIED BY 'frank';
mysql> GRANT ALL ON customer.* TO 'francis'@'localhost'
-> WITH MAX_QUERIES_PER_HOUR 20
-> MAX_UPDATES_PER_HOUR 10
-> MAX_CONNECTIONS_PER_HOUR 5
-> MAX_USER_CONNECTIONS 2;
对于grant中的MAX_USER_CONNECTIONS是限制并发连接数,若为0,则由max_user_connections系统变量确定并发连接个数,如果系统变量也为0则不限制。
如果要修改使用 grant usage来修改。如:
mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'
-> WITH MAX_QUERIES_PER_HOUR 100;
如果要删除限制就设置为0:
mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'
-> WITH MAX_CONNECTIONS_PER_HOUR 0;
如果grant设置的MAX_USER_CONNECTIONS会覆盖系统变量如:
max_user_connections=10
GRANT ... TO 'user1'@'localhost' WITH MAX_USER_CONNECTIONS 0;
GRANT ... TO 'user2'@'localhost' WITH MAX_USER_CONNECTIONS 5;
GRANT ... TO 'user3'@'localhost' WITH MAX_USER_CONNECTIONS 20;
那么user1的最大并发连接数为10,user2为5,user3为20。
在user表中的,max_query,max_update,max_connections,存放了每小时的限制。max_user_connections存放了并发连接数的限制。
以下2个语句会重置所有帐号的限制:
1.使用flush user_resources语句
2.使用grant usage设置修改限制
6.3.5 设置密码
密码设置可以在create user中也可以set password:
mysql> CREATE USER 'jeffrey'@'localhost'
-> IDENTIFIED BY 'mypass';
mysql> SET PASSWORD FOR
-> 'jeffrey'@'localhost' = PASSWORD('mypass');
read_only变量可以阻止没有有SPUER权限的用户使用 set password。
还可以使用grant usage on *.*来设置密码:
mysql> GRANT USAGE ON *.* TO 'jeffrey'@'localhost'
-> IDENTIFIED BY 'mypass';
或者使用mysqladmin:
shell> mysqladmin -u user_name -h host_name password "newpwd"
设置密码的时候注意点:
1.当使用create user或者grang identified by语句的时候可以直接使用明文,服务会帮助加密
2.当使用identified by password那么需要自己先使用password()加密
3.当使用set password 的时候,要自己调用password()加密
当然可以直接修改user表,但是需要执行flush privileges。
6.3.6 密码过期和沙盘模式
6.3.6.1 密码过期工作原理
密码过期是mysql 5.6新加的功能。(在mariadb中也有password_expired但是完成不了,下面说的功能)。
用alter user 来手动过期一个用户:
ALTER USER 'myuser'@'localhost' PASSWORD EXPIRE;
执行了之后,mysql.user.password_expired变为Y。下次连接的时候用户要不进入沙盘模式,要不就无法连接。
如果进入了沙盘模式,用户只允许做:
1.set password修改密码
2.set语句
其他的操作都会被拒绝。
disconnect_on_expired_password用来判断如何处理过期帐号的连接。如果为yes,就无法连接到客户端,为no连接到客户端,并进入沙盘模式。
6.3.7 插件式验证(Pluggable Authentication)
当客户端连接到mysql服务,根据指定的验证插件来验证:
1.如果指定了验证插件,那么就用验证插件验证
2.如果没有指定验证插件,根据password的hash值,确定使用mysql_native_password还是使用mysql_old_password
插件式的验证方式,带来了2个功能:
1.可扩展验证,就是可以通过其他验证插件来验证用户登录
2.代理用户,可以让登录用户伪装成其他用户执行请求
6.3.7.1 验证插件的使用方法
1.安装插件的library到server和client
2.安装插件,可以以配置文件,也可以用install plugin
[mysqld]
plugin-load=test_plugin_server=auth_test_plugin.so
mysql> INSTALL PLUGIN test_plugin_server SONAME 'auth_test_plugin.so';
install plugin只要运行一次就可以,下次启动会自动加载插件。
3.验证插件是否安装
mysql> SHOW PLUGINSG
...
*************************** 21. row ***************************
Name: test_plugin_server
Status: ACTIVE
Type: AUTHENTICATION
Library: auth_test_plugin.so
License: GPL
4.设置帐号的验证插件
CREATE USER 'testuser'@'localhost' IDENTIFIED WITH test_plugin_server;
5.使用客户端连接
当用户连接验证的时候,服务发现是使用auth_test_plugin插件验证,那么服务端和客户端交流使用 auth_test_plugin,来验证。
6.3.8 MySQL中可用的验证插件
略
具体看文档:http://dev.mysql.com/doc/refman/5.6/en/authentication-plugins-available.html
6.3.9 代理用户(proxy user)
代理用户是a用户登录但是使用b用户的权限执行请求。a用户就是代理用户(proxy user),b用户就是被代理用户(proxied user)。
要使用代理用户必须满足:
1.当连接客户端被当做是代理用户,插件必须返回一个不同的用户名(proxied user)。
2.代理用户帐号必须有插件验证
3.代理用户必须有代理 proxied用户的权限。
如:
CREATE USER 'empl_external'@'localhost'
IDENTIFIED WITH auth_plugin AS 'auth_string';
CREATE USER 'employee'@'localhost'
IDENTIFIED BY 'employee_pass';
GRANT PROXY
ON 'employee'@'localhost'
TO 'empl_external'@'localhost';
当登录empl_external@localhost,使用current_user()返回:
mysql> SELECT USER(), CURRENT_USER();
+-------------------------+--------------------+
| USER() | CURRENT_USER() |
+-------------------------+--------------------+
| empl_external@localhost | employee@localhost |
+-------------------------+--------------------+
是否 要用identified with as由插件决定。
6.3.9.1授予PROXY权限
PROXY权限通过 grant proxy语句被授予
GRANT PROXY ON 'proxied_user
' TO 'proxy_user
';
和revoke proxy对于
REVOKE PROXY ON 'proxied_user
' FROM 'proxy_user
';
6.3.9.2 默认proxy用户
如:
CREATE USER ''@'' IDENTIFIED WITH ldap_auth AS 'O=Oracle, OU=MySQL';
CREATE USER 'developer'@'localhost' IDENTIFIED BY 'developer_pass';
CREATE USER 'manager'@'localhost' IDENTIFIED BY 'manager_pass';
GRANT PROXY ON 'manager'@'localhost' TO ''@'';
GRANT PROXY ON 'developer'@'localhost' TO ''@'';
用户登录:
mysql --user=myuser --password='myuser_pass' ...
服务找不到myuser这个用户,但是能匹配上’’@’’然后服务调用ldap_auth,使用myuser和myuser_pass作为用户名密码验证。
如果ldap_auth发现myuser_pass不是myuser的正确密码,连接失败。
如果连接成功,发现myuser是一个developer,那么就返回developer用户名给mysql服务,然后myuser使用developer的权限:
mysql> SELECT USER(), CURRENT_USER();
+------------------+---------------------+
| USER() | CURRENT_USER() |
+------------------+---------------------+
| myuser@localhost | developer@localhost |
+------------------+---------------------+
如果ldap_auth返回的是manager,则:
mysql> SELECT USER(), CURRENT_USER();
+------------------+-------------------+
| USER() | CURRENT_USER() |
+------------------+-------------------+
| myuser@localhost | manager@localhost |
+------------------+-------------------+
6.3.9.3 代理用户系统变量
主要有2个系统变量:
1.proxy_user:如果为null,表示没有启动代理,如果是以默认代理用户验证的
mysql> SELECT @@proxy_user;
+--------------+
| @@proxy_user |
+--------------+
| ''@'' |
+--------------+
2.external_user:在验证过程中被使用到,会作为插件的设置被用户验证客户端。
6.3.10 使用SSL加密连接
mysql的标准配置是尽量加快传输,所以连接是不加密的。
6.3.10.1 基本SSL概念
略
手册:http://dev.mysql.com/doc/refman/5.6/en/ssl-basics.html
6.3.10.2 为mysql配置SSL
1.如果不是支持SSL的bianry 版本,就下载安装OpenSSL
2. 如果不是支持SSL的bianry 版本,配置编译选项
shell> cmake . -DWITH_SSL=bundled
如果使用yassl,配置如下:
shell> cmake . -DWITH_SSL=system
然后编译安装
3.检查是否支持SSL
mysql> SHOW VARIABLES LIKE 'have_ssl';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_ssl | YES |
+---------------+-------+
6.3.9.10.3 使用SSL连接
使用ssl连接需要配置一下几个选项:
Ÿ --ssl-ca
identifies the Certificate Authority (CA) certificate.
Ÿ --ssl-cert
identifies the server public key certificate. This can be sent to the client and authenticated against the CA certificate that it has.
Ÿ --ssl-key
identifies the server private key.
如:
shell> mysqld --ssl-ca=ca-cert.pem
--ssl-cert=server-cert.pem
--ssl-key=server-key.pem
和服务端类似,可以端的—ssl-cert和—ssl-key指示了客户端的公钥和私钥
使用ssl连接是否要指定配置,主要依赖于帐号的设置。
如果没有给帐号设置SSL请求或者没有使用grant require SSL 语句,那么服务端必须指定—ssl-cert,--ssl-key,客户端要使用—ssl-ca
shell> mysql --ssl-ca=ca-cert.pem
如果指定了require x509那么客户端必须还要指定正确的客户端的key和证书文件
shell> mysql --ssl-ca=ca-cert.pem
--ssl-cert=client-cert.pem
--ssl-key=client-key.pem
不使用ssl可以使用—ssl=0或者 –skip-ssl,--disable-ssl
可以通过变量查看ssl_cipher
mysql> SHOW STATUS LIKE 'Ssl_cipher';
+---------------+--------------------+
| Variable_name | Value |
+---------------+--------------------+
| Ssl_cipher | DHE-RSA-AES256-SHA |
+---------------+--------------------+
6.3.10.4 SSL相关配置
具体看:http://dev.mysql.com/doc/refman/5.6/en/ssl-options.html
Name |
Cmd-Line |
Option file |
System Var |
Status Var |
Var Scope |
Dynamic |
|
|
Yes |
|
Global |
No |
|
|
|
Yes |
|
Global |
No |
|
Yes |
Yes |
|
|
|
|
|
Yes |
Yes |
|
|
|
|
|
Yes |
Yes |
|
|
Global |
No |
|
- Variable: ssl_ca |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
Global |
No |
|
- Variable: ssl_capath |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
Global |
No |
|
- Variable: ssl_cert |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
Global |
No |
|
- Variable: ssl_cipher |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
Global |
No |
|
- Variable: ssl_crl |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
Global |
No |
|
- Variable: ssl_crlpath |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
Global |
No |
|
- Variable: ssl_key |
|
|
Yes |
|
Global |
No |
Yes |
Yes |
|
|
|
|
6.3.10.5 为mysql生成证书和公钥私钥
具体看:http://dev.mysql.com/doc/refman/5.6/en/creating-ssl-certs.html
6.3.11 从windows使用ssh链接到mysql
具体看:http://dev.mysql.com/doc/refman/5.6/en/windows-and-ssh.html
6.3.12 Mysql企业版审计日志插件
审计日志插件名叫audit_log,当安装了插件后,MySQL服务会产生日志文件包括服务的活动审计记录。
安装了插件之后会写入到审计日志,日志路径由变量audit_log_file控制,默认为audit.log。
审计日志的格式为XML格式,在服务启动的时候,可以通过audit_log_format控制系统变量,设置日志格式。
由audit_log_policy控制审计的事件,默认为all,可以设置为LOGINS,QUERIES,NONE。
把日志记录格式从老的改成新的需要以下步骤:
1.停止服务
2.重命名审计日志文件
3.使用新的audit_log_format重启服务
注:
mariadb使用的审计插件和mysql 5.6不同,mariadb使用server audit
具体看:
6.3.12.1 安装审计插件
使用配置文件,或者命令行参数plugin-load设置:
[mysqld]
plugin-load=audit_log.so
或者使用install plugin加载
mysql> INSTALL PLUGIN audit_log SONAME 'audit_log.so';
使用了install plugin之后,下次启动会自动加载
使用audit-log配置文件,来强制插件初始化,否则服务启动报错。
6.3.12.2 审计日志安全性考虑
审计日志不加密,为了考虑到敏感信息安全性问题,考虑放在只能管理员和mysql启动用户访问。
6.3.12.3 审计日志
主要介绍老的格式和新的格式的字段意义
具体看:http://dev.mysql.com/doc/refman/5.6/en/audit-log-file.html
6.3.12.4 审计日志记录控制
当审计日志插件打开日志文件的时候,查看是否包含<AUDIT>根标签,若有则写入内容,当写入完成,写入</AUDIT>结束。
如果启动时已经存在日志文件,检查是否存在</AUDIT>,如果有则先截断,然后写入审计记录。如果没有</AUDIT>或者不能截断,就认为插件初始化失败。常发生于服务crash或者被kill但是审计插件任然在运行的情况。
[ERROR] Plugin 'audit_log' init function returned error.
解决办法,直接删除审计日志然后重启。
服务当审计事件发生就写入审计日志。
审计日志插件提供了一些系统变量:
1.audit_log_file:审计日志文件路径
2.audit_log_policy:用来决定审计事件,可选值:NONE,LOGINS,QUERIES.
3.audit_log_strategy:用来控制写入审计日志的方式,可取值如下:
Value |
Meaning |
ASYNCHRONOUS |
Log asynchronously, wait for space in output buffer |
PERFORMANCE |
Log asynchronously, drop request if insufficient space in output buffer |
SEMISYNCHRONOUS |
Log synchronously, permit caching by operating system |
SYNCHRONOUS |
Log synchronously, call sync() after each request |
4.audit_log_buffer_size:用来给异步审计日志写入做缓存
5.audit_log_rotate_on_size,audit_log_flush:这2个主要控制审计日志的回绕和刷新,审计日志会随着时间推移变得越来越大,为了加强磁盘空间管理,可以自动回绕,会在手动刷新并打开一个新的日志文件。
默认audit_log_rotate_on_size=0是不会回绕的,只有修改audit_log_flush才会执行刷新审计日志并重新打开。假设需要维护3个最近的审计日志如下:
1.重命名文件
shell> mv audit.log.2 audit.log.3
shell> mv audit.log.1 audit.log.2
shell> mv audit.log audit.log.1
这个时候,插件任然往当前的审计日志写,已经被重命名为了audit.log.1
2.连接到服务刷新日志文件,插件会关闭当前日志,并打开一个新的日志
mysql> SET GLOBAL audit_log_flush = ON;
当audit_log_rotate_on_size大于0,audit_log_flush=1是没有意义的,写入后文件的大小大于audit_log_rotate_on_size,服务会重命名审计日志,打开一个新的审计日志。
6.3.12.5 审计日志插件选项和变量
具体看:
http://dev.mysql.com/doc/refman/5.6/en/audit-log-plugin-options-variables.html
6.3.13 SQL-Based MySQL账号活动审计
具体看:http://dev.mysql.com/doc/refman/5.6/en/account-activity-auditing.html