How can I check if a posted file via multipart form is of image type and that it is less than a given maxsize in Go?

huangapple go评论146阅读模式
英文:

How can I check if a posted file via multipart form is of image type and that it is less than a given maxsize in Go?

问题

我想知道在将文件上传到服务器之前是否有一种方法可以检查文件的大小和类型。我担心有人故意上传非常大的文件来拖慢服务器的速度。

我只知道在将文件复制到服务器后如何检查文件的大小。我不知道如何检查文件类型。我希望在上传2GB的数据之前就能进行检查,并验证文件。

这是我目前的代码,但它首先将文件复制到服务器,这不是我想要的。

func userUploadImage(w http.ResponseWriter, r *http.Request, _ httprouter.Params) error {
    mpf, mpfh, err := r.FormFile("file")
    if err != nil {
        return nil
    }
    defer mpf.Close()

    dstFile, err := os.Create(config.UploadDir + "/img/" + mpfh.Filename)
    if err != nil {
        return err
    }
    defer dstFile.Close()

    size, err := io.Copy(dstFile, mpf)
    if err != nil {
        return err
    }

    spew.Dump(size)
    return nil
}
英文:

I would like to know if there is a way of checking the size and the type before uploading it to the server. I am worried about people trying to upload really large files to slow the server down on purpose.

I only know how to check the size of a file after I have copied it to the server. I don't know how to check the file type. I would like to do it before having to upload 2 GB of data, and then validating the file.

This is what I have so far but this copies the file to the server first which is not what I want.

func userUploadImage(w http.ResponseWriter, r *http.Request, _ httprouter.Params) error {
	mpf, mpfh, err := r.FormFile("file")
	if err != nil {
		return nil
	}
	defer mpf.Close()

	dstFile, err := os.Create(config.UploadDir + "/img/" + mpfh.Filename)
	if err != nil {
		return err
	}
	defer dstFile.Close()

	size, err := io.Copy(dstFile, mpf)
	if err != nil {
		return err
	}

	spew.Dump(size)
	return nil
}

答案1

得分: 2

为了避免大量数据上传到您的服务器,我建议将您的multipart.File(实际上是一个io.Reader)用io.LimitedReader进行包装,例如:

wrapped := io.LimitReader(mpf,10*1024*1024)    //10 MiB

然后使用wrapped读取器进行处理。这将读取指定数量的字节,然后返回EOF,因此大于10 MiB的任何内容都将被截断。

要检查接收到的数据是否为图像,您有两个选择:

  1. 使用image.Decode(io.Reader)解析数据,如果无法将数据解析为图像,它将抛出错误-这还允许您检查接收到的数据是否完整和正确。但请注意,这需要一些时间/性能。如果您之后只是丢弃解码后的图像,您可能希望避免使用此方法。请确保查看image包的godoc,因为您将需要导入您希望解码的任何格式。
  2. 检查魔数,例如PNG文件的魔数为89 50 4e 47 0d 0a 1a 0a。然而,正确的魔数并不意味着正确的图像。特别是如果将较大的图像截断为10 MiB。

如果您有足够的能力来解码每个图像,请尽量使用第一种方法-结果应该更准确,但这只是一个建议。

我不建议使用FileHeader(pkg/mime/multipart/#FileHeader)来检查文件类型,因为我认为它不可靠。但是,您可能会在其中找到有关(原始)文件大小的信息,我建议只是转储一些请求的FileHeaders。

英文:

To avoid having tons of data uploaded to your server, I recommend wrapping your multipart.File, which is essentially an io.Reader with an io.LimitedReader, like

wrapped := io.LimitReader(mpf,10*1024*1024)    //10 MiB

and then work on the wrapped reader. This will read the specified amount of bytes and then return EOF, so anything larger than 10 MiB will be truncated.

To check whether the received data is an image, you have two choices:

  1. Parse the data with image.Decode(io.Reader), that will throw an error if it can't parse the data as an image - this also allows you to check whether the received data is complete and correct. Note however that this takes some time/steals performance. Maybe you want to avoid this, if you just discard the decoded image afterwards. Be sure to check the godoc for the image package, as you will have to import any formats you expect to decode.
  2. Check the magic number, PNG files for example have 89 50 4e 47 0d 0a 1a 0a as their magic number. However, a correct magic number does not imply a correct image. Especially if you truncated larger images to 10 MiB.

If you have the power needed to decode every image at hand, go for it - the results should be more precise, but this is just a recommendation.

I would rather not check the FileHeader (pkg/mime/multipart/#FileHeader) for the file type, I expect it to be unreliable. You might, however, find information about the (original) file size in there, I recommend just dumping the FileHeaders for some requests.

huangapple
  • 本文由 发表于 2015年9月14日 16:58:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/32560810.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定