在学习自验证文件系统 SFS的过程中,SFS
几个理念给了我一些启发:
在不依赖任何外部信息的条件下,利用加解密来控制权限。
通过可以自我证明身份的路径名实现安全地获取文件数据。
在我们的业务里,设备获取人脸开门权限高度依赖中心服务器。网络的不稳定与服务器的异常下,设备需要定期的检查全量的权限,以保证数据最终一致。权限检查的过程与更新的过程都非常的耗时耗性能,尤其是在运营商网络交割的过程中,设备网络的重启会带来大量的访问请求,导致服务器压力巨大。设备进行全量的权限检查,需要在服务器获取全量的用户信息,再进行全量的遍历筛选判断,对设备性能也是一个挑战。
故有了以下设计思考:
利用SFS
的启发构建自验证文件系统,实现门禁设备人脸开门权限的更新与中心化服务器解耦与安全验证(这里是参考 SFS 的理念,而非技术或其源码);利用 ID 多次取模构建MerkleTree
结构的层级目录,实现全量的权限检查的切割,提高检索的效率。
需注意:
该文章仅是流程的设计思考,不是最终的实现。且该方法已申请专利,如有同行友商阅读到此文章,请查阅专利文件避免侵权。
目录文件结构
/sfs/
|—— hash($comunity_id)/
|—— device \
|—— hash($pub_key) \
|—— .index
|—— group_0 \
|—— .index
|—— subgroup_0 \
|—— .index
|—— subgroup_1 \
|—— subgroup_2 \
|—— subgroup_n \
|—— group_1 \
|—— group_2 \
|—— group_n \
|—— feature \
|—— hash(user_id_0:expiry_date:feature_str).1
|—— hash(user_id_1:expiry_date:feature_str).2
|—— hash(user_id_2:expiry_date:feature_str).3
|—— hash(user_id_n:expiry_date:feature_str).2
目录文件说明
/sfs/
为根目录,权限信息按小区进行分隔,目录名为小区ID的HASH
值为hash($comunity_id)
。完整路径为/sfs/hash($comunity_id)
。拥有多个小区权限用户仅占
3%
左右,也就是说在该文件系统里冗余了3%
的人脸特征值信息
。每个小区各下设一个
device
目录和feature
目录,分别为版本控制文件
与人脸特征值文件
的目录。完整路径为/sfs/hash($comunity_id)/device/
和/sfs/hash($comunity_id)/feature
。99%
设备的人脸数是低于 5000 的,设备取遍历 5000 次去对比与服务器数据的偏差,需要消耗设备与服务器大量的性能,而权限在资料录入的稳定期变动是非常小的。故对用户 ID 进行多次取模,设计了多层的目录结构(本示例中使用了 2 层)。例如:
user_id%100%10
,创建group_0~group_9
十个目录,group_1
下存放有用户有:1、11、21、31、41、51、61、71、81、91、101、111、121...
在每个group
下再取模user_id%100
,创建subgroup_0~subgroup_99
十个目录(因为 group 中已经取模过,此时不会生成 100 个目录,如group_1
下的子目录有subgroup_1、subgroup_11~subgroup_91
)。在
设备目录 /sfs/hash($comunity_id)/device/hash($pub_key)/
、分组目录
、子分组
目录下各有一个版本控制文件.index
,共同构建出了一个树结构
。版本控制文件.index
内容为JSON
格式。上一级别的version
,是下级子节点 version 集合的 Hash。任何下级的变动必然影响上级的 HASH 值,保证通过根版本文件能够快速的检索到所有的修改内容。/sfs/hash($comunity_id)/feature
存放着该小区所有用户的所有用户人脸照片特征值解析值。文件名为文件内容的 HASH 值,即hash(user_id:expiry_date:feature_str)
,不同算法厂商产生的特征值文件以后缀的形式区分,如xxxxxx.a
表示 a 算法厂商计算的值;文件内容包含用户唯一标识、权限有效期、人脸特征值;文件采用国密sm4
算法加密,密钥可采用一小区一密钥。
如何保障安全性
刚有讲到自验证文件系统的一个重要的特性,就是在不依赖任何外部信息的条件下,利用加解密来控制权限。在这文件系统中,有两个核心的数据:版本控制文件
和特征值权限文件
。
版本控制文件
/sfs/hash($comunity_id)/device/hash($pub_key)
作为设备的私有命名空间,目录访问权限控制,通过设备密钥才能访问。任何设备只能访问自己命名空间下的子目录和文件。设备删除时,只需删除设备自己命名空间的文件夹,所有文件即被销毁。
特征值权限文件
/sfs/hash($comunity_id)/feature
作为小区的所有住户的特征值权限库,目录访问权限控制,通过小区密钥才能访问。小区不在运营时,只需删除小区自己命名空间的文件夹,所有文件即被销毁。
另外,SFS 把身份验证与文件系统分开。例如我们将数据是存放在 OSS 上的,身份验证仍可以保留现有的Ali OSS STS
机制,实现设备访问 OSS 的权限管控。
如何更新文件系统
纯后端的逻辑,这里不做分析。
如何实现快速检索
利用构建MerkleTree
树形版本结构,设备按预设的规则定期去文件系统获取根版本控制文件,与本地版本进行对比。如版本有变动,则进行下钻分析找到变动的用户。文件系统中多出的用户在设备中新增,缺少的用户在设备中删除,变更的用户在设备中做更新。