Implementation of proper input validation and sanitization to prevent path traversal attacks
package main
import (
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/file/:filename", func(c *gin.Context) {
filename := c.Param("filename")
data, err := ioutil.ReadFile("./files/" + filename)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"file": string(data)})
})
r.Run()
}
In the above code, we have a simple Go application that uses the Gin web framework. The application has a single route
/file/:filename
that takes a filename as a parameter from the user and reads the file from the
./files/
directory.
The vulnerability lies in the fact that the application does not validate or sanitize the
filename
parameter before using it to construct the file path. This could lead to a Path Traversal attack where an attacker could manipulate the
filename
parameter to access files outside of the intended
./files/
directory.
For example, an attacker could send a request with a
filename
parameter of
../secret/passwords.txt
and the application would attempt to read the file at
./files/../secret/passwords.txt
, effectively accessing a file outside of the intended directory.
This lack of data validation could potentially allow an attacker to read any file that the application has access to, which could lead to the exposure of sensitive information.
package main
import (
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
)
func main() {
r := gin.Default()
r.GET("/file/:filename", func(c *gin.Context) {
filename := c.Param("filename")
// Validate filename
if !isValidFilename(filename) {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid filename"})
return
}
// Secure file access
data, err := ioutil.ReadFile(filepath.Join("./files", filename))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"file": string(data)})
})
r.Run()
}
// isValidFilename checks if a filename is valid, allowing only alphanumeric characters and specific special characters
func isValidFilename(filename string) bool {
return strings.ContainsAny(filename, "/\\\\:*?\\"<>|") == false
}
The updated code includes a function
isValidFilename
that checks if the filename contains any of the special characters that could be used in a path traversal attack (
/
,
\\
,
:
,
*
,
?
,
"
,
<
,
>
,
|
). If any of these characters are found in the filename, the function returns
false
and the request is rejected with a
400 Bad Request
response.
The
ioutil.ReadFile
function is replaced with
filepath.Join
to construct the file path. This function securely constructs the file path, ensuring that the filename does not escape the intended directory.
The filename validation and secure file access methods protect the application against path traversal attacks by ensuring that user-provided input cannot be used to access files outside of the designated directory.
In addition to these changes, it is recommended to implement proper error handling, regularly update and patch dependencies, and perform security testing and code reviews to further enhance the security of the application.