优先队列处理文件的锁定和自动解锁

本文介绍了如何通过使用优先队列技术,结合文件修改次数检查,实现在短时间内频繁被恶意操作时对文件的有效锁定,以提升网站安全性并保持业务正常运行,同时关注内存管理和堆操作细节。
摘要由CSDN通过智能技术生成

 【背景】最近要做一个防篡改的功能,一开始是采用事件型的方式实现的,结果发现会有一种情况"如果某个文件短时间一直被外部进行多次恶意操作"时,一直防也不是个事,应该在加一层防护—文件锁定,这样就舒服多了

【好处】避免短时间站点被频繁攻击,保证安全性的同时,尽量保证业务正常运行

【实现思路】

        一开始是想着用全局map去存储每一个文件的修改次数和最后一次时间,后面发现这样子操作,需要注意内存释放问题,一不小心就会导致内存泄漏的情况。

        所以盯上了一个好东西——优先队列,通过结构体进行实现

【具体实现逻辑】

        先定义了两个结构体和一个数据结构,FileInfo用于存储文件的修改次数和最后修改时间,UnlockTask用于存储待解锁的文件名和预定解锁时间。

type FileInfo struct {
    ModCount int
    LastMod  time.Time
}

type UnlockTask struct {
    FileName string
    Time     time.Time
}

type UnlockQueue []*UnlockTask

        再写下实现heap.Interface接口的方法,主要用于操作优先队列,用堆操作(如Push和Pop)来管理队列。

func (q UnlockQueue) Len() int { return len(q) }

func (q UnlockQueue) Less(i, j int) bool {
    return q[i].Time.Before(q[j].Time)
}

func (q UnlockQueue) Swap(i, j int) {
    q[i], q[j] = q[j], q[i]
}

func (q *UnlockQueue) Push(x interface{}) {
    item := x.(*UnlockTask)
    *q = append(*q, item)
}

func (q *UnlockQueue) Pop() interface{} {
    old := *q
    n := len(old)
    item := old[n-1]
    *q = old[0 : n-1]
    return item
}

主实现函数:

  • 首先,OnFileModified函数会在文件被修改时被调用,更新文件的修改次数和最后修改时间。

  • 然后,CheckFileModCount函数定时检查文件的修改次数,如果在5秒内文件被修改了10次,就会调用lockFile函数锁定文件,并将其添加到优先队列中,预定在60秒后解锁。

  • 最后,CheckUnlockQueue函数会检查优先队列,如果到了预定的解锁时间,就会调用unlockFile函数解锁文件。

// 在文件被篡改时调用这个函数
func OnFileModified(fileName string) {
    info, ok := fileMap[fileName]
    if !ok {
       info = &FileInfo{ModCount: 0, LastMod: time.Now()}
       fileMap[fileName] = info
    }
    //fmt.Printf("---检测该文件【%s】被篡改,次数+1", fileName)
    info.ModCount++
    info.LastMod = time.Now()
}

// 定时检查文件修改次数
func CheckFileModCount() {
    for fileName, info := range fileMap {
       if time.Since(info.LastMod).Seconds() < 5 && info.ModCount >= 10 {
          fmt.Printf("---检测到文件【%s】在5s内,被篡改了10次,即将封锁该文件", fileName)
          lockFile(fileName)
          queueLock.Lock()
          heap.Push(&unlockQueue, &UnlockTask{FileName: fileName, Time: time.Now().Add(60 * time.Second)})
          queueLock.Unlock()
       }
    }
}

// 检查解锁队列
func CheckUnlockQueue() {
    queueLock.Lock()
    for unlockQueue.Len() > 0 && time.Now().After(unlockQueue[0].Time) {
       task := heap.Pop(&unlockQueue).(*UnlockTask)
       unlockFile(task.FileName)
    }
    queueLock.Unlock()
}

// 锁定文件
func lockFile(fileName string) {
    cmd := exec.Command("chattr", "+i", fileName)
    err := cmd.Run()
    if err != nil {
       fmt.Printf("Error locking file %s: %v\n", fileName, err)
    }
}

// 解锁文件
func unlockFile(fileName string) {
    cmd := exec.Command("chattr", "-i", fileName)
    err := cmd.Run()
    if err != nil {
       fmt.Printf("Error unlocking file %s: %v\n", fileName, err)
    }
}

main.go 主调用函数

func main() {
    heap.Init(&core.UnlockQueue{})
    // 当文件确定被篡改时,调用这个函数
    core.OnFileModified(event.Name)
    go func() {
        for {
           core.CheckFileModCount()
           core.CheckUnlockQueue()
           time.Sleep(1 * time.Second)
        }
    }()
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值