G110:通过减压炸弹 (gosec) 的潜在 DoS 漏洞
G110: Potential DoS vulnerability via decompression bomb (gosec)
我收到以下 golintci
消息:
testdrive/utils.go:92:16: G110: Potential DoS vulnerability via decompression bomb (gosec)
if _, err := io.Copy(targetFile, fileReader); err != nil {
^
阅读相应的 CWE,我不清楚如何更正。
请指点
func unzip(archive, target string) error {
reader, err := zip.OpenReader(archive)
if err != nil {
return err
}
for _, file := range reader.File {
path := filepath.Join(target, file.Name) // nolint: gosec
if file.FileInfo().IsDir() {
if err := os.MkdirAll(path, file.Mode()); err != nil {
return err
}
continue
}
fileReader, err := file.Open()
if err != nil {
return err
}
defer fileReader.Close() // nolint: errcheck
targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer targetFile.Close() // nolint: errcheck
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
}
return nil
}
假设您正在处理压缩数据,则需要使用 io.CopyN
。
您可以尝试使用 --nocompress
标志的解决方法。但这将导致数据被包含在未压缩的状态。
查看以下 PR 和相关问题:https://github.com/go-bindata/go-bindata/pull/50
您收到的警告来自 gosec 中提供的规则。
该规则专门检测 io.Copy
在文件解压缩时的使用情况。
这是一个潜在的问题,因为 io.Copy
:
copies from src
to dst
until either EOF is reached on src
or an error occurs.
因此,恶意负载可能会导致您的程序解压缩意外的大量数据并耗尽内存,从而导致警告消息中提到的拒绝服务。
特别是,gosec 将检查 (source) 您程序的 AST 并警告您使用 io.Copy
或 io.CopyBuffer
以及以下任何一项:
"compress/gzip".NewReader
"compress/zlib".NewReader
或 NewReaderDict
"compress/bzip2".NewReader
"compress/flate".NewReader
或 NewReaderDict
"compress/lzw".NewReader
"archive/tar".NewReader
"archive/zip".NewReader
"*archive/zip".File.Open
使用 io.CopyN
removes the warning because (quote) it "copies n bytes (or until an error) from src to dst", thus giving you (the program writer) control of how many bytes to copy. So you could pass an arbitrarily large n
that you set based on the available resources of your application, or copy in chunks.
根据提供的各种指示,替换
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
和
for {
_, err := io.CopyN(targetFile, fileReader, 1024)
if err != nil {
if err == io.EOF {
break
}
return err
}
}
PS 虽然这有助于内存占用,但这无助于复制很长 and/or 无限流的 DDOS 攻击 ...
我收到以下 golintci
消息:
testdrive/utils.go:92:16: G110: Potential DoS vulnerability via decompression bomb (gosec)
if _, err := io.Copy(targetFile, fileReader); err != nil {
^
阅读相应的 CWE,我不清楚如何更正。
请指点
func unzip(archive, target string) error {
reader, err := zip.OpenReader(archive)
if err != nil {
return err
}
for _, file := range reader.File {
path := filepath.Join(target, file.Name) // nolint: gosec
if file.FileInfo().IsDir() {
if err := os.MkdirAll(path, file.Mode()); err != nil {
return err
}
continue
}
fileReader, err := file.Open()
if err != nil {
return err
}
defer fileReader.Close() // nolint: errcheck
targetFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer targetFile.Close() // nolint: errcheck
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
}
return nil
}
假设您正在处理压缩数据,则需要使用 io.CopyN
。
您可以尝试使用 --nocompress
标志的解决方法。但这将导致数据被包含在未压缩的状态。
查看以下 PR 和相关问题:https://github.com/go-bindata/go-bindata/pull/50
您收到的警告来自 gosec 中提供的规则。
该规则专门检测 io.Copy
在文件解压缩时的使用情况。
这是一个潜在的问题,因为 io.Copy
:
copies from
src
todst
until either EOF is reached onsrc
or an error occurs.
因此,恶意负载可能会导致您的程序解压缩意外的大量数据并耗尽内存,从而导致警告消息中提到的拒绝服务。
特别是,gosec 将检查 (source) 您程序的 AST 并警告您使用 io.Copy
或 io.CopyBuffer
以及以下任何一项:
"compress/gzip".NewReader
"compress/zlib".NewReader
或NewReaderDict
"compress/bzip2".NewReader
"compress/flate".NewReader
或NewReaderDict
"compress/lzw".NewReader
"archive/tar".NewReader
"archive/zip".NewReader
"*archive/zip".File.Open
使用 io.CopyN
removes the warning because (quote) it "copies n bytes (or until an error) from src to dst", thus giving you (the program writer) control of how many bytes to copy. So you could pass an arbitrarily large n
that you set based on the available resources of your application, or copy in chunks.
根据提供的各种指示,替换
if _, err := io.Copy(targetFile, fileReader); err != nil {
return err
}
和
for {
_, err := io.CopyN(targetFile, fileReader, 1024)
if err != nil {
if err == io.EOF {
break
}
return err
}
}
PS 虽然这有助于内存占用,但这无助于复制很长 and/or 无限流的 DDOS 攻击 ...