bugfix: 修复zip的slip问题,防止上传恶意zip,增强服务器安全性。

pull/798/head
Go-Go-Farther 2022-06-20 13:54:53 +08:00
parent edc96294e6
commit 940cc2420c
2 changed files with 24 additions and 5 deletions

View File

@ -699,6 +699,8 @@ func (book *Book) ImportBook(zipPath string, lang string) error {
} }
//如果加压缩失败 //如果加压缩失败
if err := ziptil.Unzip(zipPath, tempPath); err != nil { if err := ziptil.Unzip(zipPath, tempPath); err != nil {
logs.Error("CAll ziptil.Unzip error, zipPath: %s, tempPath: %s, err: %v",
zipPath, tempPath, err)
return err return err
} }
//当导入结束后,删除临时文件 //当导入结束后,删除临时文件

View File

@ -2,6 +2,7 @@ package ziptil
import ( import (
"archive/zip" "archive/zip"
"fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
@ -13,7 +14,7 @@ import (
//@param dest 需要解压到的目录 //@param dest 需要解压到的目录
//@return err 返回错误 //@return err 返回错误
func Unzip(zipFile, dest string) (err error) { func Unzip(zipFile, dest string) (err error) {
dest = strings.TrimSuffix(dest, "/") + "/" dest = strings.TrimSuffix(dest, "/") + "/" // Make sure suffix with "/".
// 打开一个zip格式文件 // 打开一个zip格式文件
r, err := zip.OpenReader(zipFile) r, err := zip.OpenReader(zipFile)
if err != nil { if err != nil {
@ -22,10 +23,26 @@ func Unzip(zipFile, dest string) (err error) {
defer r.Close() defer r.Close()
// 迭代压缩文件中的文件,打印出文件中的内容 // 迭代压缩文件中的文件,打印出文件中的内容
for _, f := range r.File { for _, f := range r.File {
if !f.FileInfo().IsDir() { //非目录且不包含__MACOSX if !f.FileInfo().IsDir() {
if folder := dest + filepath.Dir(f.Name); !strings.Contains(folder, "__MACOSX") { path := filepath.Join(dest, f.Name)
os.MkdirAll(folder, 0777)
if fcreate, err := os.Create(dest + strings.TrimPrefix(f.Name, "./")); err == nil { // logs.Debug("file name: ", f.Name, ",dest:", dest,
// ",absolute path: ", filepath.Join(dest, f.Name),
// ",absolute dir: ", filepath.Dir(path),
// ",relative dir: ", filepath.Dir(f.Name))
if dir := filepath.Dir(path); !strings.Contains(dir, "__MACOSX") {
// This branch : 非目录且不包含__MACOSX目录
/* Resolve the Zip Slip problem.(Solution: The decompressed file must be in the DEST directory.)
References: https://github.com/golang/go/issues/25849
https://github.com/mholt/archiver/blob/e4ef56d48eb029648b0e895bb0b6a393ef0829c3/archiver.go#L110-L119 */
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("illegal file path: %s", path)
}
os.MkdirAll(dir, 0777)
if fcreate, err := os.Create(path); err == nil {
if rc, err := f.Open(); err == nil { if rc, err := f.Open(); err == nil {
io.Copy(fcreate, rc) io.Copy(fcreate, rc)
rc.Close() //不要用defer来关闭如果文件太多的话会报too many open files 的错误 rc.Close() //不要用defer来关闭如果文件太多的话会报too many open files 的错误