G110:通过减压炸弹 (gosec) 的潜在 DoS 漏洞

gli*_*tak 6 static-analysis go golint

我收到以下golintci消息:

testdrive/utils.go:92:16: G110: Potential DoS vulnerability via decompression bomb (gosec)
    if _, err := io.Copy(targetFile, fileReader); err != nil {
                 ^
Run Code Online (Sandbox Code Playgroud)

阅读相应的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
}
Run Code Online (Sandbox Code Playgroud)

bla*_*een 7

您收到的警告来自gosec中提供的规则。

io.Copy该规则专门检测文件解压缩的使用。

这是一个潜在的问题,因为io.Copy

复制从srcdst直到到达 EOFsrc或发生错误。

因此,恶意有效负载可能会导致您的程序解压缩意外大量的数据并耗尽内存,从而导致警告消息中提到的拒绝服务。

特别是,gosec 将检查(来源)您程序的 AST,并警告您使用以下任何一项io.Copyio.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删除警告,因为(引用)它“从 src 复制 n 个字节(或直到出现错误)到 dst ”,从而使您(程序编写者)可以控制要复制的字节数。n因此,您可以传递根据应用程序的可用资源设置的任意大值,或者分块复制


gli*_*tak 1

根据提供的各种指针,替换

if _, err := io.Copy(targetFile, fileReader); err != nil {
  return err
}
Run Code Online (Sandbox Code Playgroud)

for {
  _, err := io.CopyN(targetFile, fileReader, 1024)
  if err != nil {
    if err == io.EOF {
      break
    }
    return err
  }
}
Run Code Online (Sandbox Code Playgroud)

PS,虽然这有助于内存占用,但这无助于复制很长和/或无限流的 DDOS 攻击......

  • 另外,我想知道替换是否应该使用“errors.Is(err, io.EOF)” (2认同)