Home >Backend Development >Golang >How can I simplify and secure file decompression using Go's zip package?

How can I simplify and secure file decompression using Go's zip package?

Barbara Streisand
Barbara StreisandOriginal
2024-11-14 14:54:02410browse

How can I simplify and secure file decompression using Go's zip package?

Simple and Effective File Decompression in Go

Decompressing ZIP archives in Go can be a straightforward process. One approach, as demonstrated by the original code, involves manually handling the decompression for each file within the archive.

However, there's a more seamless and efficient way to accomplish this using the following updated solution:

func Unzip(src, dest string) error {
    r, err := zip.OpenReader(src)
    if err != nil {
        return err
    }
    defer func() {
        if err := r.Close(); err != nil {
            panic(err)
        }
    }()

    os.MkdirAll(dest, 0755)

    // Closure to wrap file extraction and writing, avoiding deferred stack overflow
    extractAndWriteFile := func(f *zip.File) error {
        rc, err := f.Open()
        if err != nil {
            return err
        }
        defer func() {
            if err := rc.Close(); err != nil {
                panic(err)
            }
        }()

        path := filepath.Join(dest, f.Name)

        // Check for directory traversal (ZipSlip) vulnerability
        if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
            return fmt.Errorf("illegal file path: %s", path)
        }

        if f.FileInfo().IsDir() {
            os.MkdirAll(path, f.Mode())
        } else {
            os.MkdirAll(filepath.Dir(path), f.Mode())
            f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
            if err != nil {
                return err
            }
            defer func() {
                if err := f.Close(); err != nil {
                    panic(err)
                }
            }()

            _, err = io.Copy(f, rc)
            if err != nil {
                return err
            }
        }

        return nil
    }

    for _, f := range r.File {
        err := extractAndWriteFile(f)
        if err != nil {
            return err
        }
    }

    return nil
}

This updated solution offers several advantages:

  • Deferred Close() Errors Handled: It gracefully handles potential errors in closing both the file reader (rc) and the archive reader (r), ensuring proper cleanup even in the face of failures.
  • Closure-Wrapped File Extraction: The extraction and writing process for each file is encapsulated within a closure, eliminating the need for stacking and cleaning up multiple defer .Close() calls for each file.
  • Directory Creation: The solution ensures that the destination directory exists before extracting files, preventing any extraction failures.
  • ZipSlip Prevention: It includes a security check to prevent potential directory traversal (ZipSlip) vulnerabilities by verifying that files are not extracted outside the expected destination directory.

With these enhancements, this code provides a simple, robust, and secure method for unzipping files in Go.

The above is the detailed content of How can I simplify and secure file decompression using Go's zip package?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn