在学习自验证文件系统 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树形版本结构,设备按预设的规则定期去文件系统获取根版本控制文件,与本地版本进行对比。如版本有变动,则进行下钻分析找到变动的用户。文件系统中多出的用户在设备中新增,缺少的用户在设备中删除,变更的用户在设备中做更新。