Prevention of unauthorized access to sensitive files on the server
package main
import (
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/readfile", func(c *gin.Context) {
filepath := c.Query("filepath")
data, err := ioutil.ReadFile(filepath)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.String(http.StatusOK, string(data))
})
r.Run()
}
The above Go code uses the Gin web framework to create a simple web server. The server has a single endpoint,
/readfile
, which reads a file from the server's filesystem and returns its content.
The file path is taken directly from the
filepath
query parameter in the GET request. This is done using the
c.Query("filepath")
function call. The file at that path is then read using
ioutil.ReadFile(filepath)
, and its content is returned as a response.
The major vulnerability in this code is Local File Inclusion (LFI). This vulnerability occurs because the application uses input from the user to construct a file path to read, without properly validating or sanitizing the input. This can allow an attacker to read any file on the system that the web server has access to, simply by providing a path to that file. For example, an attacker could use this vulnerability to read sensitive files like
/etc/passwd
.
To exploit this vulnerability, an attacker could send a GET request to the
/readfile
endpoint with a
filepath
query parameter that includes a relative or absolute path to a file they want to read. For example,
http://localhost:8080/readfile?filepath=/etc/passwd
.
This vulnerability can lead to serious security issues, like information disclosure, and can potentially be used as a stepping stone for further attacks, like Remote Code Execution (RCE), if the server also interprets the file content.
package main
import (
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
)
func main() {
r := gin.Default()
r.GET("/readfile", func(c *gin.Context) {
inputPath := c.Query("filepath")
// 1. Validate user input
if inputPath == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "File path is required"})
return
}
// 2. Restrict access to specific directories
// 4. Use absolute file paths
basePath := "/path/to/allowed/directory"
absPath := filepath.Join(basePath, filepath.Clean("/"+inputPath))
// 3. Sanitize user input
if !strings.HasPrefix(absPath, basePath) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid file path"})
return
}
data, err := ioutil.ReadFile(absPath)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.String(http.StatusOK, string(data))
})
r.Run()
}
The updated code includes several measures to prevent local file inclusion vulnerabilities:
1. Validate user input: The code checks if the
filepath
query parameter is provided. If not, it returns a
400 Bad Request
error.
2. Restrict access to specific directories: The code defines a
basePath
which is the only directory that the user can access. This is a form of whitelisting, which is more secure than blacklisting (trying to block access to specific directories).
3. Sanitize user input: The
filepath.Clean
function is used to remove any
..
or similar sequences from the input path. Then, the code checks if the resulting absolute path still starts with the
basePath
. If not, it returns a
400 Bad Request
error.
4. Use absolute file paths: The
filepath.Join
function is used to construct an absolute path from the
basePath
and the sanitized input path. This ensures that the application only accesses files within the
basePath
directory.
Please note that this code does not implement the following measures:
- Implement access controls: Depending on your application, you might want to add additional checks to ensure that the user is authorized to access the requested file.
- Implement file permissions: You should ensure that the file permissions on your server are set up correctly to prevent unauthorized access.
- Use a secure file handling library: This code uses the standard
ioutil.ReadFile
function to read the file. If you are dealing with more complex file operations, you might want to consider using a library that provides additional security features.