FUSE 文件系统 - 使用 securefs 实现文件系统透明加解密
题外话:最近作者去了西安,对唐朝的历史产生了浓厚的兴趣,B 站 up 主渤海小史 笔者关注了一两年了,最近正好出了一半书《大唐气象》,看了几期视频,感觉非常好,推荐给大家!
1. 背景
为了满足应用程序对敏感数据的安全存储需求,我们需要一个透明的文件系统。该文件系统需要能够在应用程序无需额外处理的情况下,自动完成数据的加密与解密,以保证数据的机密性和完整性。
相关文章:
2. securefs
2.1 securefs 介绍
securefs 是一个基于 FUSE 的用户态文件系统,专注于提供安全、透明的文件加密功能。其主要特点包括:
• 文件加密:透明加密文件内容与文件名,用户无需感知。
• 跨平台支持:兼容
Linux、macOS和Windows。• 高性能:通过分块加密和多线程加速提升操作效率。
• 灵活配置:支持用户选择加密算法和模式。
• 易用性:通过简单的命令行工具实现挂载、解挂载与加密文件夹管理。
主页:https://github.com/netheril96/securefs
完整命令参考:https://github.com/netheril96/securefs/blob/master/docs/usage.md
2.2 securefs 原理与关键技术点
2.2.1 文件系统原理
• FUSE 支持:
• 使用 FUSE 提供用户态文件系统接口,挂载加密文件夹。
• 实现了
read,write,readdir等核心回调函数。• 透明加密:
• 文件内容在写入时加密,读取时解密,用户操作无感知。
• 文件名和元数据(如大小、时间戳)也可加密。
2.2.2 加密机制
• 文件内容加密:
• 使用分块加密方式(通常 4KB 或 64KB),支持随机访问。
• 支持 AES-CBC 和 AES-GCM 等模式:
• AES-CBC 需要唯一的初始化向量(IV)。
• AES-GCM 提供数据完整性验证。
• 文件名加密:
• 加密后的文件名存储在底层文件系统中,通过 Base64 或 Hex 编码。
• 密钥管理:
• 使用 PBKDF2 或 Argon2 派生强加密密钥。
• 加密密钥仅在内存中临时存储,避免明文存储。
2.2.3 性能优化
• 分块加密:仅对访问的块执行加解密操作,减少不必要的开销。
• 缓存机制:对解密后的数据进行短期缓存,减少重复计算。
• 多线程并发:利用多核 CPU 性能,加速加密和解密过程。
2.2.4 跨平台实现
• 基于 libfuse(Linux/macOS)和 WinFSP(Windows)实现跨平台支持。
• 使用 OpenSSL 等通用密码库确保加密兼容性。
2.3 安全性分析
2.3.1 数据加密
• 使用 AES 算法提供高强度数据加密,保障机密性。
• AES-GCM 提供完整性验证,防止数据被篡改。
2.3.2 文件名加密
• 文件名加密避免泄露文件结构信息,但可能对性能有一定影响。
2.3.3 抗暴力破解
• 密钥派生函数(PBKDF2 或 Argon2)加入随机盐,增强密码抗性。
• 限制暴力破解所需的计算资源,提高安全性。
2.3.4 降低攻击面
• 用户态文件系统限制对内核的直接操作,减少潜在漏洞。
• 不在磁盘存储明文密钥,避免密钥泄露风险。
2.4 应用场景
• 个人隐私保护:
• 适合对本地敏感文件夹进行加密存储,保护隐私。
• 企业数据保护:
• 提供透明的加密存储,适合企业文件存储和共享的安全需求。
• 云存储安全:
• 加密数据后上传至云端,确保数据即使被窃取也不可解读。
• 安全文件传输:
• 通过挂载加密的文件夹,保障传输过程中的数据安全。
3. 验证
目标设计
• 使用 securefs 将 /encrypted 目录作为加密文件存储路径;
• 将 /mnt/secure 作为明文视图挂载点,应用程序通过 VFS 接口访问 /mnt/secure,无需感知加密解密逻辑;
• 自动完成挂载、卸载以及清理工作,确保加密文件系统的安全性和使用便捷性;
• 程序需要在容器中运行(即需要用 namespace 做进程间隔离)。
非目标
• 防止 root 用户访问加密后的数据(可以解密):因为 securefs 是以 fuse 文件系统方式,因此即使用 namespace 隔离,root 用户仍然可以通过 nsenter 进入到进程的 mnt namespace 中 查看。
如果要实现进程级别的文件访问安全,首先需要在进程中直接进行文件内容的加密和解密,此外需要防止恶意用户(包括 root 用户)获取到密钥。
3.1 准备工作
我们需要准备以下文件。
ll
-rw-r--r-- 1 root root 937 Jan 16 04:02 Dockerfile
-rwxr-xr-x 1 root root 761 Jan 16 05:18 entrypoint.sh*
-rwxrwxrwx 1 root root 4725040 Apr 22 2024 securefs*每个文件的说明如下。
3.1.1 Dockerfile
cat Dockerfile
# 使用 Ubuntu 20.04 作为基础镜像
FROM ubuntu:20.04# 设置环境变量,避免交互式安装提示
ENV DEBIAN_FRONTEND=noninteractive
# 备份原始 sources.list 文件并替换为国内镜像源,安装依赖
RUN cp /etc/apt/sources.list /etc/apt/sources.list.bak && \
sed -i 's|http://archive.ubuntu.com/ubuntu/|http://mirrors.aliyun.com/ubuntu/|g' /etc/apt/sources.list && \
sed -i 's|http://security.ubuntu.com/ubuntu/|http://mirrors.aliyun.com/ubuntu/|g' /etc/apt/sources.list && \
apt update && \
apt install -y --no-install-recommends libfuse-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
COPY securefs /usr/bin/securefs
# 复制启动脚本到容器中
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
# 确保启动脚本具有可执行权限
RUN chmod +x /usr/local/bin/entrypoint.sh
# 设置启动脚本为容器的默认入口点
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
3.1.2 entrypoint.sh
cat entrypoint.sh
#!/bin/bash# 定义加密目录和挂载点
ENC_DIR="/encrypted"
MOUNT_DIR="/mnt/secure"
# 确保目录存在
mkdir -p "$ENC_DIR" "$MOUNT_DIR"
# 检查是否已经创建加密文件系统
if [ ! -f "$ENC_DIR/.securefs.json" ]; then
echo "Creating a new encrypted filesystem in $ENC_DIR"
securefs create "$ENC_DIR" --pass "your-password"
fi
# 挂载加密文件系统
echo "Mounting encrypted filesystem from $ENC_DIR to $MOUNT_DIR"
securefs mount -b "$ENC_DIR" "$MOUNT_DIR" --pass "your-password"
# 设置挂载目录的权限,仅允许当前用户访问
chmod 700 "$MOUNT_DIR"
# 捕获退出信号,确保容器停止时卸载加密文件系统
trap "securefs unmount $MOUNT_DIR; exit" SIGINT SIGTERM EXIT
# 启动容器的主要进程
exec "$@"
3.3.3 securefs 可执行文件
当前 release 包的地址:https://github.com/netheril96/securefs/releases/tag/v1.0.0
wget https://github.com/netheril96/securefs/releases/download/v1.0.0/securefs-linux-amd64-release.zip
unzip securefs-linux-amd64-release.zip
chmod +x securefs3.2 构建镜像
docker build -t securefs:v1 .
3.3 运行
docker run --rm -d --privileged -e SECUREFS_PASSWORD=your-password -v /encrypted:/encrypted securefs:v1 sleep 3603.4 验证
docker psdocker exec -it <container_id> /bin/bash
findmnt -l | grep secure
/mnt/secure securefs fuse.securefs rw,nosuid,nodev,relatime,user_id=0,group_id=0
ll /mnt/secure/
total 4
drwxr-xr-x 2 root root 70 Jan 16 03:40 ./
drwxr-xr-x 1 root root 20 Jan 16 05:40 ../
echo "aaaabbbbb" > /mnt/secure/a.txt
ll /mnt/secure/
total 4
drwxr-xr-x 2 root root 70 Jan 16 03:40 ./
drwxr-xr-x 1 root root 20 Jan 16 05:40 ../
-rw-r--r-- 1 root root 10 Jan 16 05:45 a.txt
cat /mnt/secure/a.txt
aaaabbbbb
# 从容器中退出
exit
# 主机上执行
ll /encrypted/
total 12
drwxr-xr-x 2 root root 70 Jan 16 03:40 ./
drwxr-xr-x 23 root root 4096 Jan 16 03:38 ../
-rw-r--r-- 1 root root 570 Jan 16 03:39 .securefs.json
-rw-r--r-- 1 root root 54 Jan 16 05:45 V6CCZUUT7KEPPIVABAW226RFRZZAQHT7VA
4. 更多方案对比
参考:https://nuetzlich.net/gocryptfs/comparison/
4.1 概述
| 项目名称 | 首次发布 | 编程语言 | 许可证 | 开发状态 | 平台支持 | 用户界面 | 反向模式支持 |
| gocryptfs | 2015 | Go | MIT | 活跃 | Linux、macOS,第三方支持 Windows 和 Android | 命令行界面(CLI),第三方图形界面(GUI) | 是(自 v1.1 起,支持只读) |
| EncFS | 2003 | C++ | LGPLv3 / GPLv3 | 维护中 | Linux、macOS,第三方支持 Windows | 命令行界面(CLI),第三方图形界面(GUI) | 是(有限的写入支持) |
| eCryptFS | 2006 | C | GPLv2 | 活跃 | Linux | 集成于登录过程 | 否 |
| Cryptomator | 2014 | Java | GPLv3 | 活跃 | Linux、macOS、Windows | 图形界面(GUI),第三方命令行界面(CLI) | 否 |
| securefs | 2015 | C++ | MIT | 活跃 | Linux、macOS、Windows | 命令行界面(CLI),第三方图形界面(GUI) | 否 |
| CryFS | 2015 | C++ | LGPLv3 | 活跃 | Linux、macOS、Windows(实验性) | 命令行界面(CLI),第三方图形界面(GUI) | 否 |
4.2 一般安全性
| 项目名称 | 文档可用性 | 密码哈希算法 |
| gocryptfs | 是 | scrypt |
| EncFS | 是 | PBKDF2 |
| eCryptFS | 否 | 无(在外部工具中实现) |
| Cryptomator | 是 | scrypt |
| securefs | 是 | PBKDF2 |
| CryFS | 是 | scrypt |
4.3 文件内容加密
| 项目名称 | 加密算法 | 完整性保护 | 文件大小混淆 |
| gocryptfs | GCM | 是 | 否 |
| EncFS | CBC | 否 | 否 |
| eCryptFS | CBC | 否 | 是(4 KB 增量) |
| Cryptomator | CTR | 是 | 否 |
| securefs | GCM | 是 | 否 |
| CryFS | GCM | 是 | 是(分块存储) |
4.4 文件名加密
| 项目名称 | 加密算法 | 前缀泄漏 | 相同名称泄漏 | 最大名称长度 | 最大路径长度 | 目录扁平化 |
| gocryptfs | EME | 否 | 否 | 255 字符 | 4095 字符 | 否 |
| EncFS | CBC | 否 | 否 | 175 字符 | 4095 字符 | 否 |
| eCryptFS | CBC | 是 | 是 | 143 字符 | 4095 字符 | 否 |
| Cryptomator | AES-SIV | 否 | 否 | 1024 字符 | 4095 字符 | 是 |
| securefs | AES-SIV | 否 | 否 | 143 字符 | 4095 字符 | 是 |
| CryFS | GCM | 否 | 否 | 1024 字符 | 4095 字符 | 是 |