引入文件结构保护的原因
随着越来越多的工作、数据被迁移到服务器及存储上,对于这些作为业务基础的软硬件的安全性和可靠性,我们需要提高关注度,并在尽可能的范围内提高这种可靠性,以保障工作的平稳顺利开展。
针 对不同的内容,我们可以采取不同的安全保障策略。比方说,对于服务器的灾难恢复,比较方便而合适的办法是用双机热备,备机通过监视主机运行状况,实现尽可 能快地恢复服务。而对于资料的存储,我们多是会选择一些实践证明了的比较可靠的数据备份和恢复方法,这些方法多是基于某种特定的数据库的,或者是数据库自 身提供的。
以上两点内容是大多数管理者想得到并且可以做得不错的,我们常常会忽略一点是,作为提供某种服务的程序本身的安全性。打个比方说,提供
web
服务的
apache
, 其配置和一些附属的文件可能遭到破坏,而且即便是有操作系统锁级的保护,进程也可能被恶意停止,进而破坏文件。拓展开来讲,任何以文件或者文件树形式存储 的数据的安全性,一向被忽略。其结果是,我们不得不重新安装服务并配置参数,这不是一项轻松的工作,尤其是对于一些复杂的程序而言。
虽然针对不同服务的保护各不相同,但一般都需要涉及到对于该服务的文件结构保护,在此基础上在做一些进程的恢复工作等。
文件结构保护系统的架构
除了必要的防杀毒软件之外,还需要一些更一般的保护手段,因为病毒库的更新总是有滞后性的。这些手段包括建立文件结构信息备份、实时监控和文件恢复等。
首 先,在确定系统一切正常的前提下,对于需要进行保护的文件结构,我们需要采集能唯一标识该结构的必要信息,至少包括一个描述文件结构的数据结构和在其中每 一个文件的唯一标记。就前者而言,可以是一个多叉树或者向量,这个根据不同的工具的特性具体而定;文件唯一标记可以通过计算整个文件的
md5
码来得到,这也是现阶段在网络上发布文件尤其是大型文件时,保证文件完整性的一个通用做法,比如说
ubuntu
的发布。除了多叉树或向量数据结构需要驻留本地之外,其他的必要信息连同文件结构中所有有效文件将存储到一个可以保证安全的位置,这个位置一般是一台被隔离的服务器,通过有限的端口与存在受保护文件结构的服务器相连接,也就是监控端。
完 成了文件结构的备份之后,将建立服务器之间的监控关系。因为文件遍历的本地性特点,所以主逻辑即数据结构与文件结构之间的比较需要在被监控段实现。根据比 较之后的结果,包括被恶意添加或删除的文件,做出是否恢复或删除的决定。而具体到每一个文件的完整性检测,则需要被监测端将当前次文件遍历中得到的
md5
码,发送至监测端进行比较。因此,从最终的实现来看,服务器两端之间的关系并不能完全用监控来描述,事实上被监控端将负责起遍历文件结构的工作,而监控端将主要负责
md5
码比较和文件恢复的功能。
最后在监控端,通过一定的途径连接监控程序和备份信息,实现文件按顺序有效地回传,这样就基本上形成了一个文件结构保护系统的框架。
需要注意的一些细节
文件结构信息的采集需要在系统建立之初就准备就绪,然后通过人工拷贝的方法移植到监控端。这个采集过程相对来说比较简单,只需要一次文件结构的遍历就可以实现。监控端的信息存储可以考虑使用数据库,而在存储文件的时候,根据具体的回传特点可以直接存储在文件系统之下或者以
blob
的形式存入数据库。
相比于略显简单的初始化,保护系统实现的关键环节在于文件结构与数据结构的比较以及如何准确地回传文件。
首 先数据结构的建立需要在保护系统启动的初始化环节完成,之后它将作为整个系统运行的基础,循环地将文件结构与它进行对比。而该对比过程可以通过两种方法来 实现。第一:两次遍历,即数据结构和文件结构遍历。这么做的好处是实现难度不大,尤其是在文件结构遍历部分,可以任意选择深度或广度遍历。但是针对遍历中 每个节点遇到的文件或文件夹,不得不查询一次数据结构,对于设计不佳的数据结构,这么做的结果可能又是一次遍历,这就增加了运行的时长。第二:一次遍历, 即在数据结构和文件结构同时以一种相对协调的步调向下遍历。这里所说的向下即是说,需要在完成本层次遍历的基础上才能继续下一个层次,也就是层次优先遍 历。这样的做法需要在设计上保证数据结构与文件结构具有类似性,而对于层次的控制也完全依靠人工逻辑完成,但在运行上将获得比前一种方法快一个数量级以上 的优势。
在文件回传方面,由于存在很大可能性是需要恢复的一个文件列表,所以应准确控制其中每一个文件恢复的启动与截至。可以采用架设
ftp
服务器的方法,在传输单文件时阻塞本地剩余传输队列中的文件。在这里采用了这种模式,但未直接使用
ftp
,而是采用了一种简化的模拟方式:被监控端维护一个文件处理队列,通过阻塞的方式和先进先出的顺序来处理
文件句柄
;建立了两个
socket
连接,其中之一在监控端接受被监控端发出的指令并启动数据传输,另一个在被监控端接受来自监控端的文件传输完成信号并关闭本地文件句柄,然后通知启动下一个文件传输。
Perl
实现的几点建议
一:
对于这种通过网络来连接的服务,整体的框架可以考虑使用
poe
,这将极大地减少底层代码的维护量,而将精力主要集中到业务逻辑的实现上来。尤其是在合理利用
component
的情况下,一段几十行的
socket
代码可能会被压缩为短短几行。更为重要的是,
poe
在单线程内实现了多任务模式,虽然依旧会阻塞在长任务执行过程中,但这方便各个任务之间信息的传递和资源的共享。对于未来其他模块功能的增加,也
提供了
一个可扩展的基础。比如,需要为客户端提供一个可视的操作界面,只需引入
Tk
,
poe
会在变量表中自动添加根元素
$poe_main_window
。
二:
由于文件结构信息的量一般不是很大,因此在事先未安装其他数据库的情况下,信息的存储可以考虑使用轻量级的
sqlite
。它没有守护进程,一般以嵌入的形式
服务
于各个
任务
中。
三:
体现文件结构逻辑的数据结构,可以使用
hash
表来实现,在这里
hash
表起得是多叉树的作用。打个比方,针对绝对路径
d:\sources\perl\frs\md5_check.pl
其数据结构将是
:
$base->{d}->{sources}->{perl}->{frs}->{md5_check.pl} = ’f’
也就是说任意的目录是一个
hash
引用,而最终的文件节点是一个内容为“
f
”的
text
变量。那么在遍历时,就可以通过
ref
节点类型来判断是目录还是文件。
四:
在处理关闭文件传输的指令时,可以考虑使用
ikc
来远程调用本地指令,这实际上是简化了由远程发指令、本地翻译再到本地指令执行这一连串的过程,用在这里也方便未来丰富远程指令。