Insecure File Management

Why is this important?

Any functionality related to file management requires careful usage. If attackers are able to influence the input to file access related APIs, then it can have a serious impact. For example, attackers could read all files on your application server.

In other cases this can allow attackers to include their own code, or files, that are then executed by the application at runtime.

Check out this video for a high-level explanation on local file inclusion issues:

Local File Inclusion

Fixing Insecure File Management

Option A: Use FilePath.Base() and Verify Extensions

  1. Go through the issues that GuardRails identified in the PR.
  2. A vulnerable example is shown below:

     package main
     import (
         "fmt"
         "log"
         "net/http"
         "os"
     )
     func main() {
         http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
             // The insecure user input is coming from the title parameter
             title := r.URL.Query().Get("title")
             // and used to directly open a file.
             // By using ../../../ attackers can access any file in any folder
             // such as the /etc/passwd file, or files containing sensitive data
             f, err := os.Open(title)
             if err != nil {
                 fmt.Printf("Error: %v\n", err)
             }
             body := make([]byte, 5)
             if _, err = f.Read(body); err != nil {
                 fmt.Printf("Error: %v\n", err)
             }
             fmt.Fprintf(w, "%s", body)
         })
         log.Fatal(http.ListenAndServe(":3000", nil))
     }
    
  3. Replace it with the following:

     package main
     import (
         "fmt"
         "log"
         "net/http"
         "os"
         "strings"
         // Import https://golang.org/pkg/path/filepath/#Base
         "path/filepath"
     )
     // Create function to check for valid extensions
     func isValidExtension(ext string) bool {
         switch ext {
         case
             ".jpg",
             ".jpeg",
             ".png":
             return true
         }
         return false
     }
     func main() {
         http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
             // We are using filepath.Base to ensure the last element of the
             // path is returned.
             // https://golang.org/pkg/path/filepath/#Base
             title := filepath.Base(r.URL.Query().Get("title"))
             // You should also check for the correct file extension
             // This is done with https://golang.org/pkg/path/filepath/#Ext
             extension := strings.ToLower(filepath.Ext(title))
             // Call the function to check for allowed extensions
             // and only perform the read action the extensions is as expected
             if isValidExtension(extension) {
                 f, err := os.Open(title)
                 if err != nil {
                     fmt.Printf("Error: %v\n", err)
                 }
                 body := make([]byte, 5)
                 if _, err = f.Read(body); err != nil {
                     fmt.Printf("Error: %v\n", err)
                 }
                 fmt.Fprintf(w, "%s", body)
             }else{
                 log.Print("Not permitted file extension was encountered.")
             }
         })
         log.Fatal(http.ListenAndServe(":3000", nil))
     }
    
  4. Test it

  5. Ship it 🚢 and relax 🌴

Option B: Don't Store Files Locally

Another option is to store files in the cloud. This way local file inclusion attacks can be prevented. Some of the options are:

More information: