Go项目golintci报G110解压炸弹DoS漏洞(gosec) 求教修复方法
解压函数G110解压炸弹漏洞修复方案
报错本质
G110是gosec规则检测到代码使用无大小限制的io.Copy处理zip压缩包内容,存在解压炸弹DoS风险:攻击者可以构造极小体积的恶意压缩包,解压后产生远超磁盘容量的内容,直接占满磁盘导致服务不可用,正好对应CWE-409定义的“高压缩比导致的资源消耗异常”场景。
具体修复步骤
- 替换无限制的拷贝逻辑,设置单文件解压大小上限
不能直接使用裸io.Copy把压缩包内容写入磁盘,需要根据业务场景定义单文件允许的最大解压体积(比如结合业务实际需要,设为100MB),配合io.LimitReader做读入侧限制,同时统计实际写入磁盘的字节数,超过阈值就中断解压流程返回错误。
原代码中对应io.Copy的逻辑替换示例:
这里在阈值基础上加1的目的,是避免边界判断漏过:如果解压内容刚好超过阈值1字节,也能被准确捕获触发中断。// 单文件最大解压阈值100MB,可根据业务实际调整 const maxSingleFileSize = 100 << 20 written, err := io.Copy(targetFile, io.LimitReader(fileReader, maxSingleFileSize+1)) if err != nil { return err } // 实际写入大小超过阈值时,判定为解压炸弹中断流程 if written > maxSingleFileSize { return fmt.Errorf("压缩包内文件 %s 解压大小超过允许上限,疑似恶意压缩包", file.Name) } - 增加累计解压总大小的全局校验
仅限制单文件大小不足以完全防御解压炸弹,攻击者可以拆分多个刚好低于单阈值的恶意文件,累计写入撑满磁盘。需要在解压循环外定义累计写入大小的变量,每完成一个文件的写入就累加实际写入的字节数,累计值超过预设的总解压阈值(比如1GB)时,直接中断整个解压流程返回错误。 - 不要直接屏蔽规则检查
不要在io.Copy那行直接加// nolint: gosec屏蔽告警,这种操作只是隐藏了提示,没有实际消除解压炸弹的风险。gosec触发G110告警的核心判断逻辑,就是检测到直接将zip文件的reader传入io.Copy、没有任何大小校验的代码片段,只有替换成带大小限制的拷贝逻辑,才能从根源上通过规则检测。
配套安全加固补充
当前代码中已经通过注释跳过了路径拼接的安全检查,实际解压时还需要校验拼接后的文件路径是否完全落在目标解压目录下,防止恶意zip构造包含相对路径跳转的文件名,把文件写到解压目录之外的位置。
内容的提问来源于stack exchange,提问作者gliptak
相关产品推荐
相关产品推荐

