简单几招提高MySQL安全性

导读

如何提高MySQL的安全性

数据库的安全性无疑很重要,这里教大家几招简单方法提高安全性。

1. 正确设置 datadir 权限模式

关于 datadir 正确的权限模式是 0750,甚至是 0700。
也就是最多只允许 mysqld 进程属主用户及其所在用户组可访问,但只有属主可修改文件。
最好是直接设置成 0700,相对更安全些,避免数据文件意外泄漏。

[yejr@imysql.com]# chown -R mysql.mysql /data/mysql57
[yejr@imysql.com]# chmod 0700 /data/mysql57

[yejr@imysql.com]# ls -la /data/
drwxr-x---.  8 mysql mysql 4096 Feb 14 08:08 mysql57

2. 将 mysql socket 文件放在 datadir 下

很多人习惯将 mysql socket文件放在 /tmp 目录下,尤其是跑多实例时,/tmp 目录下可能有 mysql3306.sock、mysql3307.sock、mysql3308.sock 等多个这样的文件。
要注意,mysql.sock 文件默认的权限模式是 0777,也就是任何人都有机会通过 /tmp 目录下的 socket 文件直接登入 mysql,尤其是root密码为空或弱密码,并且还允许本地 socket 方式登入时,是个比较危险的安全隐患。
因此,我们强烈建议把 mysql socket 文件放置在每个实例自己的 datadir 下,并且参考第一条建议,设置正确的权限模式。

[yejr@imysql.com]# chmod 0700 /data/mysql57/mysql.sock

[yejr@imysql.com]# ls -la /data/mysql57/mysql.sock
srwx------. 1 mysql mysql 0 Feb 12 16:00 /data/mysql57/mysql.sock

3. 使用login-path

一般来说,我们会为每个mysql账户设置密码,这样是安全了,但使用和维护起来就不方便了,每次都要输入密码,尤其是调用mysql client工具时,如果直接将密码写在client工具的选项里,则是非常危险的行为,从历史命令就能看到密码了,会有类似下面的提示:

mysql: [Warning] Using a password on the command line interface can be insecure.

这时候,我们其实可以利用login-path功能来提高安全性及便利性。这个特性是MySQL 5.6新增的。
首先,利用 mysql_config_editor 配置login-path:

#选项 ”-G lp-mysql57-3306”设定login-path的别名
mysql_config_editor set -G lp-mysql57-3306 -S /data/mysql57/mysql.sock -uroot -p

设置完后,就会在该用户的家目录下生成 .mylogin.cnf 文件:

[yejr@imysql.com]# ls -la ~/.mylogin.cnf
-rw-------. 1 yejr users 152 Feb 11 22:42 /home/yejr/.mylogin.cnf

[yejr@imysql.com]# file ~/.mylogin.cnf
/home/yejr/.mylogin.cnf: data

这是个加密的二进制文件,即便用明文方式查看,也是无法显示密码的:

[yejr@imysql.com]# mysql_config_editor print --all
mysql_config_editor print --all
[lp-mysql57-13306]
user = root
password = *****
socket = /data/mysql57/mysql.sock

接下来可以利用 login-path 很方便的登入 mysqld 而无需额外的密码:

[yejr@imysql.com]# mysql --login-path=lp-mysql57-13306 -e "select 1+1 from dual"
+-----+
| 1+1 |
+-----+
|   2 |
+-----+

[yejr@imysql.com]# mysqladmin --login-path=lp-mysql57-13306 pr
+----+------+-----------+----+---------+------+----------+------------------+
| Id | User | Host      | db | Command | Time | State    | Info             |
+----+------+-----------+----+---------+------+----------+------------------+
| 3  | root | localhost |    | Query   | 0    | starting | show processlist |
+----+------+-----------+----+---------+------+----------+------------------+

在做好前面两条安全规则的前提下,即便万一家目录下的 .mylogin.cnf 文件被其他普通用户盗取,也无法利用 socket 方式登入 mysql,当然了,除非你之前在 login-path 里设置的是走 tcp/ip 方式,那就悲剧了~

下面是假设 yejr 普通账号想利用 root 账号的 .mylogin.cnf 文件登入,报告失败,因为无法访问 /data/mysql57/mysql.sock 文件:

[yejr@imysql ~]$ /usr/local/mysql57/bin/mysql --login-path=lp-mysql57-13306
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/data/mysql57/mysql.sock' (13)

4. 防范误操作

为了避免通过mysql cli客户端工具误操作执行全表更新/删除,以及大数据量的SELECT、JOIN,可以在 my.cnf 的 [mysql] 区间里设置下面几个选项:

[mysql]
safe-updates
select_limit=4294967295
max_join_size=4294967295

这样就可以避免通过mysql cli客户端工具执行类似下面的SQL了:

DELETE FROM t;
UPDATE t set c=?;
DELETE FROM t WHERE non_key = ?;
UPDATE t set c=? WHERE non_key = ?;

除非是改成像下面这样的:

UPDATE t SET not_key_column=? LIMIT 1;
DELETE FROM t LIMIT 1;

延伸阅读

MySQL安全手册

数据是企业核心资产,数据对企业而言是最重要的工作之一。稍有不慎,极有可能发生数据无意泄露,甚至被黑客恶意窃取的风险。每年业界都会传出几起大事件,某知名或不知名的公司被脱裤(拖库的谐音,意思是整个数据库被黑客盗取)之类的。

从数据安全上也可以分为外网安全及内部操作安全,下面分别讨论一下。
内部操作安全策略

1. 是否回收DBA全部权限

试想,如果DBA没权限了,日常DB运维的活,以及紧急故障处理,该怎么实施呢?因此,建议在没有成熟的自动化运维平台前,不应该粗暴的回收DBA的太多权限,否则可能会导致工作效率降低的,甚至DBA有一种不被信任的负面情绪。

2. MySQL层安全策略

• 业务帐号最多只可以通过内网远程登录,而不能通过公网远程连接。
• 增加运维平台账号,该账号允许从专用的管理平台服务器远程连接。当然了,要对管理平台部署所在服务器做好安全措施以及必要的安全审计策略。
• 建议启用数据库审计功能。这需要使用MySQL企业版,或者Percona/MariaDB分支版本,MySQL社区版本不支持该功能。
• 启用 safe-update 选项,避免没有 WHERE 条件的全表数据被修改;
• 在应用中尽量不直接DELETE删除数据,而是设置一个标志位就好了。需要真正删除时,交由DBA先备份后再物理删除,避免误操作删除全部数据。
• 还可以采用触发器来做一些辅助功能,比如防止黑客恶意篡改数据。

3. MySQL账号权限规则

• 业务帐号,权限最小化,坚决不允许DROP、TRUNCATE权限。
• 业务账号默认只授予普通的DML所需权限,也就是select、update、insert、delete、execute等几个权限,其余不给。
• MySQL初始化后,先行删除无用账号,删除匿名test数据库

mysql> delete from mysql.user where user!='root' or host!='localhost'; flush privileges;

mysql> drop database test;

• 创建备份专用账号,只有SELECT权限,且只允许本机可登入。
• 设置MySQL账号的密码安全策略,包括长度、复杂性。

4. 关于数据备份

记住,做好数据全量备份是系统崩溃无法修复时的最后一概救命稻草。
备份数据还可以用来做数据审计或是用于数据仓库的数据源拉取之用。
一般来说,备份策略是这样的:每天一次全备,并且定期对binlog做增备,或者直接利用binlog server机制将binlog传输到其他远程主机上。有了全备+binlog,就可以按需恢复到任何时间点。
特别提醒:当采用xtrabackup的流式备份时,考虑采用加密传输,避免备份数据被恶意截取。
外网安全策略
事实上,操作系统安及应用安全要比数据库自身的安全策略更重要。同理,应用程序及其所在的服务器端的系统安全也很重要,很多数据安全事件,都是通过代码漏洞入侵到应用服务器,再去探测数据库,最后成功拖库。

5. 操作系统安全建议

• 运行MySQL的Linux必须只运行在内部网络,不允许直接对公网暴露,实在有需要从公网连接的话,再通过跳板机做端口转发,并且如上面所述,要严格限制数据库账号权限级别。
• 系统账号都改成基于ssh key认证,不允许远程密码登入,且ssh key的算法、长度有要求以确保相对安全。这样就没有密码丢失的风险,除非个人的私钥被盗。
• 进一步的话,甚至可以对全部服务器启用PAM认证,做到账号的统一管理,也更方便、安全。
• 关闭不必要的系统服务,只开必须的进程,例如 mysqld、sshd、networking、crond、syslogd 等服务,其它的都关闭。
• 禁止root账号远程登录。
• 禁止用root账号启动mysqld等普通业务服务进程。
• sshd服务的端口号建议修改成10000以上。
• 在不影响性能的前提下,尽可能启用对MySQL服务端口的防火墙策略(高并发时,采用iptables可能影响性能,建议改用ip route策略)。
• GRUB必须设置密码,物理服务器的Idrac/imm/ilo等账号默认密码也要修改。
• 每个需要登入系统的员工,都使用每个人私有帐号,而不是使用公共账号。
• 应该启用系统层的操作审计,记录所有ssh日志,或利bash记录相应的操作命令并发送到远程服务器,然后进行相应的安全审计,及时发现不安全操作。
• 正确设置MySQL及其他数据库服务相关目录权限,不要全是755,一般750就够了。
• 可以考虑部署堡垒机,所有连接远程服务器都需要先通过堡垒机,堡垒机上就可以实现所有操作记录以及审计功能了。
• 脚本加密对安全性提升其实没太大帮助。对有经验的黑客来说,只要有系统登入权限,就可以通过提权等方式轻松获得root。

6. 应用安全建议

• 禁用web server的autoindex配置。
• 从制度层面,杜绝员工将代码上传到外部github上,因为很可能存在内部IP、账号密码泄露的风险,真的要上传必须先经过安全审核。
• 尽量不要在公网上使用开源的cms、blog、论坛等系统,除非做过代码安全审计,或者事先做好安全策略。这类系统一般都是黑客重点研究对象,很容易被搞;
• 在web server层,可以用一些安全模块,比如nginx的WAF模块;
• 在app server层,可以做好代码安全审计、安全扫描,防止XSS攻击、CSRF攻击、SQL注入、文件上传攻击、绕过cookie检测等安全漏洞;
• 应用程序中涉及账号密码的地方例如JDBC连接串配置,尽量把明文密码采用加密方式存储,再利用内部私有的解密工具进行反解密后再使用。或者可以让应用程序先用中间账号连接proxy层,再由proxy连接MySQL,避免应用层直连MySQL;

最后我们想说,任何高明的安全策略,都不如内部员工的安全意识来的重要。以前发生过一起案例,公司内有位员工的PC不慎中毒,结果导致内网数据被盗。

安全无小事,每个人都应铭记于心。在数据安全面前,可以适当牺牲一些便利性,当然也不能太过,否则可能得不偿失。

全文完。


扫码加入叶老师的「MySQL核心优化课」,开启MySQL的修行之旅吧。

FAQ系列 | 防范SQL注入风险

0、导读

在MySQL里,如何识别并且避免发生SQL注入风险

1、关于SQL注入

互联网很危险,信息及数据安全很重要,SQL注入是最常见的入侵手段之一,其技术门槛低、成本低、收益大,颇受各层次的黑客们所青睐。

一般来说,SQL注入的手法是利用各种机会将恶意SQL代码添加到程序参数中,并最终被服务器端执行,造成不良后果。

例如,我们访问接口 http://imysql.com/user.php?userid=123 来根据userid获取用户信息,假设程序中是这么处理的:

$sql = “SELECT * FROM user WHERE userid = $_GET[userid]“;

上面这段代码看起来既low有很xx对吧,尤其是在双引号里面还可以直接引用数据类型变量,所以说php是世界上最好的语言一点不为过,哈哈(其实我早期也写过几年php的)。

这时候,如果我们传递进去的参数改成这样:http://imysql.com/user.php?userid=123 or 1=1,这就会导致SQL条件永远成立,所有的数据都会被读取出来。又或者可以传递这样的参数:http://imysql.com/user.php?userid=123 or if(now()=sysdate(),sleep(5),1),这时候不但所有的数据都会被读取到,也会让这个SQL执行完毕后再等待5秒才能返回,黑客可据此来判断这个SQL注入探测是否成功。

在上面这个例子中,其实我们只需要对用户输入的参数进行简单的类型判断和控制,即可快速避免被注入的风险,例如改成下面这样就可以了:

$userid = intval(strim($_GET[‘userid’]));

$sql = “SELECT * FROM user WHERE userid = “ . mysql_real_escape_string($userid);

可见,至少基础的SQL注入并不难防范,只要在各个层面都做足工作就可以。而简单的SQL盲注(就是乱拳打死老师傅的玩法)已经可以采用sqlmap之类的辅助工具来做了,完全不需要人工执行。

2、如何防范

上面提到过sqlmap,它既可以作为SQL盲注的工具,也可以在新项目上线前内部扫一次,提前发现潜在漏洞,及时修补,反过来为我们所用。其他可以检测sql注入漏洞的知名扫描工具有:SQLIer、SQLID、SQL Power Injector、SQLNinja

我们也可以自己通过频繁扫描当前执行的SQL列表,根据一些关键字来判断是否发生了SQL注入或潜在风险,常见的关键字有:

  • SLEEP() — 一般的SQL盲注都会伴随SLEEP()函数出现,而且一般至少SLEEP 5秒以上
  • MID()
  • CHAR()
  • ORD()
  • SYSDATE()
  • SUBSTRING()
  • DATABASES()
  • SCHEMA()
  • USER()
  • VERSION()
  • CURRENT_USER()
  • LOAD_FILE()
  • OUTFILE/DUMPFILE
  • INFORMATION_SCHEMA
  • TABLE_NAME
  • fwrite()/fopen()/file_get_contents() — 这几个是PHP文件操作函数

我们可以以较高频率检查当前的活跃SQL命令,一旦发现上述关键字,可以立即记录下来并触发告警,通知管理员及时人工确认处理,甚至也可以先直接自动杀掉这些SQL查询(可以用 pt-kill 工具来做到这点,也可以自行开发),以防万一,少给黑客留机会。

还有,我们建议把选项 safe-update/sql_safe_updates 设置为 1,防止没有任何 WHERE 条件的误操作更新,将全表数据都写错

3、其他建议

防范SQL注入只是数据安全保护工作很小的一部分,只要做好基本功就可以防住至少80%以上的SQL注入探测。

在app server层,以PHP开发语言为例,除了上面提到的规范用户输入类型外,还可以改成用 sprintf() 函数来格式化构造 SQL 语句,也可以一定程度防范SQL注入。还可以修改 php cgi 程序的运行属主为普通用户,最起码不能使用 root 用户,避免因为代码层不严谨导致被黑客上传可执行 php 程序代码文件。还可以把php中的远程文件调用权限关闭,把选项 allow_url_fopen、allow_url_include 均设置为 off,并限定php可以打开的文件目录,不允许跨区域访问敏感文件。

除了在代码层面做好数据类型判断、用户输入判断外,还可以在web server层加上过滤策略,比如在nginx上启用WAF插件。或者,也可以购买IDC运营商、云主机提供商提供的商业解决方案。对于重视数据安全的企业来说,花点钱保平安更为重要。

4、附录

下面是一些常见SQL注入参考案例:

案例1:SELECT * FROM t WHERE a LIKE ‘%xxx%’ OR (IF(NOW=SYSDATE(), SLEEP(5), 1)) OR b LIKE ‘1=1‘;

案例2:SELECT * FROM t WHERE a > 0 AND b IN(497 AND (SELECT * FROM (SELECT(SLEEP(20)))a));

案例3:SELECT * FROM t WHERE a=1 and b in (1234,(SELECT (CASE WHEN (5=5) THEN SLEEP(5) ELSE 5*(SELECT 5 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END)));

 

关于MySQL的方方面面大家想了解什么,可以直接留言回复,我会从中选择一些热门话题进行分享。 同时希望大家多多转发,多一些阅读量是老叶继续努力分享的绝佳助力,谢谢大家 :)

最后打个广告,运维圈人士专属铁观音茶叶微店上线了,访问:http://yejinrong.com 获得专属优惠

MySQL安全策略

0、导读

MySQL被运用于越来越多的业务中,在关键业务中对数据安全性的要求也更高,如何保证MySQL的数据安全?

MySQL被运用于越来越多的业务中,在关键业务中对数据安全性的要求也更高,如何保证MySQL的数据安全。

数据安全如果只靠MySQL应用层面显然是不够的,是需要在多个层面来保护的,包括网络、系统、逻辑应用层、数据库层等。

下面是我们可借鉴的一些安全策略。

1、网络、系统层面

在这个层面可以做很多的事情,我们可以把这些安全要求作为新系统安装时的标准要求,放到自动化装机方案中。

  • 把运行MySQL的服务器放在内网中,不要启用公网;
  • 迫不得已启用公网的话,修改sshd端口到10000以上;
  • 设置防火墙策略,只允许信任的服务器连接sshd和MySQL端口;
  • 修改idrac/imm密码,设置GRUB密码;
  • 设置密码安全策略,比如要求 PASS_MIN_LEN 不低于8位,其实最好是直接用一个复杂密码做MD5之后再作为正式密码,32位长度的安全程度够高吧;
  • 将操作日志记入syslog并且发送到远程log server上,坚决不能只存储在本地;
  • 除了必须的账号,其他的都设为无登入权限;
  • 尽量把运行MySQL的服务器独立出来,不要和web server、app server放一起。必须放一起的话,也要设置好权限分离,不允许web server、app server进程的属主有直接访问MySQL datadir的权限;
  • 禁用web server层的autoindex配置;
  • 可能的话,采用https代替http;
  • 关键应用保持更新,避免老版本的漏洞风险;
  • 设置nginx、php等应用服务的安全策略,禁用危险函数等;
  • 可以考虑购买运营商提供的一些安全防护、扫描器等产品;
  • 坚决杜绝二逼行为,把关键配置文件上传到公共网络上(如把公司项目代码放在github上作为个人项目,内含内网账号密码信息)。

2、逻辑应用层

在这个层面,等多的是依赖运营及开发人员的安全意识,很多本可以避免的低级安全漏洞完全可以在这个层面处理掉,比如下面提到的XSS、CSRF、SQL注入等漏洞。

  • 尽量不要在公网上使用开源的cms、blog、论坛等系统,除非做过代码安全审计,或者事先做好安全策略。这类系统一般都是黑客重点研究对象,很容易被搞;
  • 在web server层,可以用一些安全模块,比如nginx的WAF模块;
  • 在app server层,可以做好代码安全审计、安全扫描,防止XSS攻击、CSRF攻击、SQL注入、文件上传攻击、绕过cookie检测等安全漏洞;
  • 应用程序中涉及账号密码的地方例如JDBC连接串配置,尽量把明文密码采用加密方式存储,再利用内部私有的解密工具进行反解密后再使用。或者可以让应用程序先用中间账号连接proxy层,再由proxy连接MySQL,避免应用层直连MySQL;
  • 应用层启用关键日志记录,例如交易日志,方便后续对账什么的。

3、MySQL数据库层

前面几层如果都做的不够安全的话,在这层也几乎是岌岌可危了。但我们依然可以做些事情的。

  • 启用 safe-update 选项,避免没有 WHERE 条件的全表数据被修改;
  • 将 binlog 的保存周期加长,便于后续的审计、审查;
  • 应用账号只赋予SELECT、UPDATE、INSERT权限,取消DELETE权限。把需要DELETE权限的逻辑改成用UPDATE实现,避免被物理删除;
  • 需要真正删除时,交由DBA先备份后再物理删除;
  • 可以采用Percona的SQL审计插件,据说还有macfee的插件;
  • 还可以采用触发器来做一些辅助功能,比如防止黑客恶意篡改数据。

4、后记

数据安全可以做的事情很多,本文也只是罗列了一些比较简单可快速实施的方案。每个企业应有自己的安全策略规范,每一位参与者都应该心怀敬畏,努力遵守这些必要的规范,不使信息安全成为空谈。

真正的数据安全,是靠所有人的意识安全作为支撑的,没有这个意识靠机制、制度、工具都是不靠谱。

 

关于MySQL的方方面面大家想了解什么,可以直接留言回复,我会从中选择一些热门话题进行分享。 同时希望大家多多转发,多一些阅读量是老叶继续努力分享的绝佳助力,谢谢大家 :)

最后打个广告,运维圈人士专属铁观音茶叶微店上线了,访问:http://yejinrong.com 获得专属优惠