Centos7、Mysql8.0 load_file函数返回为空的终极解决方法--暨selinux的深入理解

零、问题背景

最近想换房,为了方便自己对比感兴趣的房子,因此决定将目标房源的基本信息放在表里,特别是要一目了然的看到众多房子的各种图纸和照片,因此决定要在Mysql8.0.34数据库中以二进制形式保存图片(抛开合理性和性能暂且不谈,这里只说技术实现),许多帖子说使用load_file函数来实现,但我按照其他人的方法实操时一直返回NULL,还好历经千辛万苦终于解决了,现将过程与思路加以总结,存档留念。

一、准备工作

1.1、服务器与数据库版本

我是用 rpm 方式安装的 MySQL 8.0.23 版本,服务器操作系统是Centos 7.9 虚拟机资源 2C 4G 40G

1.2、表结构

下图是我的表结构,其中有几个字段是 mediumblob类型,用来存放大小约为200k以内的图片。

1.3、图片保存位置

为了便于后续业务扩展,也出于数据隔离的需要,我用服务器上自定义了 /data/pic/house 路径作为当前业务存储图片的根目录。并在其下面创建了 housepic 和 roomtype两个路径。

二、问题分步展示

2.1、问题展示

我将一张名为 h_1.jpg 的图片放到 /data/pic/house/roomtype 下,然后使用如下语句尝试查看图片时没能返回预期图片内容,而是返回了NULL。

sql 复制代码
select load_file('/data/pic/house/roomtype/h_1.jpg');

2.2、原因及secure_file_priv介绍

load_file 函数返回为 null 的原因,根源在于 MySQL 配置文件中的 "secure_file_priv" 属性取值与load_file 函数使用的路径不一。在具体解决问题之前,应该先了解这一属性的作用和取值范围是什么。

2.2.1、secure_file_priv介绍

该属性有三类取值,分别为 "NULL"、空值、具体路径字符串。不同取值的含义如下表所示

|-------------|----------------------|
| 取值 | 含义 |
| NULL | 不允许读写任何路径下的文件 |
| '' 或 没有值 | 允许读写任意路径下的文件 |
| 字符串(如 /tmp) | 允许读写当前路径(如 /tmp)下的文件 |

2.2.2、secure_file_priv 查看

在MySQL任意一种客户端中输入如下命令查看。secure_file_priv的默认取值如下图所示,为 "/var/lib/mysql-files/"。说明当前load_file 函数只能操作 "/var/lib/mysql-files/" 路径下的文件。

sql 复制代码
show variables like '%secure%';
2.2.3、secure_file_priv 修改

通过上面的分析已经知道了问题的原因,下面就是在MySQL的配置文件中修改这一参数的取值。因为我的MySQL是rpm安装版,所以配置文件的名称与路径为: /etc/my.cnf (其他版本操作系统下的MySQL的配置文件位置与名称请自行确认)。同时我希望 MySQL 不限制文件路径,因此 secure_file_priv 取值及展示如下所示:

cs 复制代码
#关闭mysql的文件读写路径限制,取值为空
secure-file-priv= ''

需要注意的一点就是,配置文件中应写成 "secure-file-priv" 而非"secure_file_priv"的形式,切切!

2.3、效果与终极解决方法

如果逐位按照上面的方法作了修改,大概率是依然不成功。原因在于没有关闭selinux 。我之前就在selinux 这个坑中挣扎了好久才爬出来。下面就简单聊聊 selinux 是啥,以及为什么会对这个参数有这么大的影响。

2.3.1、selinux是什么、能做什么

它是"安全增强型 Linux(Security-Enhanced Linux)"的简称,它是 Linux 的一个安全子系统。

它能对linux系统中,包括root在内的所有用户的行为做管制。它能通过一系列的配置实现 "允许 X 目标,对 Z 对象/资源,做 Y行为 " (May <subject> do <action> to <object/source>)的访问控制。其中,X多指进程;Y多指X访问的资源,如端口、文件等;Z多指访问或操作规则。

它有三种工作模式,如下表所示:

|------------|-----------------------------|
| 模式名称 | 作用 |
| enforcing | 强制模式。阻止并在日志记录违反SELinux规则的行为 |
| permissive | 宽容模式。仅在日志记录违反SELinux规则的行为 |
| disabled | 关闭模式。关闭SELinux |

selinux 是一套相当复杂的子系统,里面有庞大的配置项需要了解,在此不做进一步的解释,只需要知道它会对 MySQL 的关键行为做校验与限制即可。除非是专门负责安全和服务器运维的工程师需要深入了解selinux各种规则之外,一般的开发人员在遇到linux 的一些校验失败的情况时,可以想到有这样一个东西存在,并且知道通过关闭selinux可以解决大部分的安全校验问题即可。

2.3.2、selinux 的关闭与开启

selinux 的关闭分为临时关闭和永久关闭,下图为临时关闭方式(即设为宽容模式)

下面为永久关闭方法

cpp 复制代码
# 修改 /etc/selinux/config 文件中的  SELINUX=disabled
[root@MySQL01 ~]# vim /etc/selinux/config

# 修改 /etc/sysconfig/selinux 文件中的  SELINUX=disabled
[root@MySQL01 ~]# vim /etc/sysconfig/selinux

2.4、最终效果

在MySQL 的 secure_file_priv参数设置为理想的值,并且关闭了 selinux 之后,发现可以正常读取到图片了,如下图所示

2.5、补充说明

存放图片的路径,建议放到 mysql 属组,且赋予 对应的权限。如下图所示

三、说在最后

9.1 如何查看centos 版本

bash 复制代码
cat /etc/redhat-release

9.2、如何查看MySQL版本

sql 复制代码
select VERSION(); 

9.3、load_file 函数的作用与效率

它在 MySQL 中的主要作用是读取本地或远程的文件。文件种类涵盖文本、二进制、图片、视频等。因这样的读取方式不够安全,因此建议在受信的环境中使用。

9.4、MySQL 几种操作图片的思路和对比

可以通过load_file 函数将图片记录到字段中,也可以将图片所在的路径记录到字段中。前者存在安全隐患,后者无法在MySQL中直接看到图片内容。因此对图片的处理方式应根据业务需求等因素综合考虑后选择。

相关推荐
一只搬砖的猹1 小时前
cJson系列——常用cJson库函数
linux·前端·javascript·python·物联网·mysql·json
冰镇毛衣1 小时前
4.3 数据库HAVING语句
数据库·sql·mysql
zhenryx2 小时前
微涉全栈(react,axios,node,mysql)
前端·mysql·react.js
ROCKY_8178 小时前
Mysql复习(二)
数据库·mysql·oracle
问道飞鱼10 小时前
【知识科普】认识正则表达式
数据库·mysql·正则表达式
HaiFan.11 小时前
SpringBoot 事务
java·数据库·spring boot·sql·mysql
上山的月12 小时前
MySQL -函数和约束
数据库·mysql
zhcf12 小时前
【MySQL】十三,关于MySQL的全文索引
数据库·mysql
丁总学Java12 小时前
要查询 `user` 表中 `we_chat_open_id` 列不为空的用户数量
数据库·mysql
抓哇能手12 小时前
数据库系统概论
数据库·人工智能·sql·mysql·计算机