从浏览器(客户端)接收文件的最安全方式是什么?

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

What is the most secure way to upload a file receiving from browser(client)?

问题

我正在使用Golang编写一个Web应用程序,现在正在编写文件上传部分,但我不知道最安全的方法是什么。

有人可以给我一些信息吗?谢谢。

**编辑:**我的意思是如何防止用户将文件上传到我不想要的位置。用户可能修改文件名以导致它被上传到特定目录。有没有办法防止这种情况发生?

我还想问一下,像Web Shell这样的黑客技术是否适用于使用Golang编写的Web应用程序?我认为不适用,但我想核实一下我的想法是否正确。

英文:

I am writing a web app using Golang, and I am writing the file upload part now, but I don't know what is the most secure way to do it.

Can anyone give me some information? Thanks.

Edit: I mean how to prevent users upload their file to the position other than the position I want. User may modify the filename to cause it to be uploaded to a specific directory. Are there any way to prevent it?

And I want to ask if the hacking technique like web shell workable to the web app written in Golang? I think is not, but I want to check if my thinking is right.

答案1

得分: 2

您的服务器接收到一个文件(例如通过表单提交),您的服务器代码负责将其保存到服务器选择的文件夹中。

客户端无法控制服务器将文件保存在何处。客户端可以任意建议一个文件夹,例如使用另一个表单字段(或相对于某个约定或任意根目录的子文件夹),但客户端无法强制执行任何操作。

您应该注意的一件事是,如果在服务器端获取了提交的文件名,您不应该直接使用它,因为客户端可能发送一个包含文件夹分隔符(例如'/')和用于表示父文件夹的序列(例如"../..")的文件名。

您应该做的事情(最安全的方式)是在服务器端生成一个文件名。或者,如果您想使用客户端推荐的名称,只使用发送的文件名的最后一部分(如果它也包含文件夹名称)。此外,如果使用客户端发送的名称,您应该检查文件是否已经存在,以防止独立的客户端覆盖彼此的文件。或者最好使用一个对客户端唯一的文件夹名称,这样就不会有机会覆盖彼此的文件。

您可以使用path包来检查/操作文件名和路径。例如,path.Base()只返回路径的最后一部分(文件名)。您可以使用path.Join()来连接文件夹和文件名。

例如,如果客户端通过表单提交上传文件,您可以在服务器端像这样处理它:

func fileHandler(w http.ResponseWriter, r *http.Request) {
    f, fh, err := r.FormFile("file")
    if err != nil {
        // 未提交文件?处理错误
        http.Error(w, "You must upload a file", http.StatusBadRequest)
        return
    }

    // 保存文件:
    // 这里我使用用户名作为唯一的客户端标识符
    saveName := path.Join("path/to/uploaded/files/", username, path.Base(fh.Filename))
    savef, err := os.Create(saveName)
    if err != nil {
        // 在服务器上创建文件失败,处理错误
        http.Error(w, "Failed to save file", http.StatusInternalServerError)
        return
    }
    defer savef.Close()

    io.Copy(savef, f)
    fmt.Fprintln(w, "File saved successfully.")
}
英文:

Your server receives a file (e.g. via a form post), and your server code is responsible to save it to a folder of the server's choice.

The client has no control over where the server will save it. The client may arbitrarily recommend a folder e.g. with another form field (or a subfolder relative to some agreed or arbitrary root), but the client is not in a position to enforce anything.

One thing you should be aware of that if you acquire the posted file name at server side, you should not use it as is, because the client may send a file name which contains folder separators (e.g. '/' and it may contain sequences to denote parent folders (e.g. "../..").

What you should do (most secure) is to generate a name at the server side. Or if you want to use the name recommended by the client, only use the last part of the sent file name (in case it contains folder names too). Also if you use the name sent by the client, you should check if file already exists to prevent independent clients to overwrite each other's files. Or best would be to use a folder name unique to the client, that way there is no chance to overwrite each other's files.

You may use the path package to check/manipulate file names and paths. For example path.Base() returns only the last part (the file name) of a path. And you may use path.Join() to concatenate folders and file name.

For example if a client uploads a file via a form post, you may handle it at server side like this:

func fileHandler(w http.ResponseWriter, r *http.Request) {
    f, fh, err := r.FormFile("file")
    if err != nil {
        // File not submitted? Handle error 
        http.Error(w, "You must upload a file", http.StatusBadRequest)
        return
    }

    // Save it:
    // Here I use username as a unique client identifier
    saveName := path.Join("path/to/uploaded/files/", username, path.Base(fh.Filename))
    savef, err := os.Create(saveName)
    if err != nil {
        // Failed to create file on server, handle err
        http.Error(w, "Failed to save file", http.StatusInternalServerError)
        return
    }
    defer savef.Close()

    io.Copy(savef, f)
    fmt.Fprintln(w, "File saved successfully.")
}

huangapple
  • 本文由 发表于 2016年1月27日 13:09:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/35029311.html
匿名

发表评论

匿名网友

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

确定