Implementation of proper input validation and sanitization for the host header
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
host := c.Request.Host
c.Redirect(302, "http://"+host+"/malicious")
})
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
In the above code, we have a simple Gin application with one route,
/
. This route retrieves the host from the incoming request with
c.Request.Host
and then redirects the client to a new URL that includes the original host in its structure.
The vulnerability lies in the fact that the
Host
header can be manipulated by an attacker. This means that the attacker can set the
Host
header to a malicious website, and the application will redirect the user to this malicious website.
This is a Host Header Injection vulnerability because the application uses user-supplied data (the
Host
header in the HTTP request) in the
Location
header of an HTTP response without validating it. This can lead to unintended behavior such as redirecting users to malicious websites.
The code does not validate or sanitize the
Host
header from the client's request before using it to construct the redirect URL, which means an attacker can manipulate the
Host
header to control the application's flow.
In this case, the application is vulnerable to phishing attacks, as an attacker can redirect users to a malicious site that looks like the original site but is controlled by the attacker. Users may then unwittingly provide sensitive information such as login credentials to the attacker.
package main
import (
"github.com/gin-gonic/gin"
"net/url"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
host := c.Request.Host
// Validate the host header
if isValidHost(host) {
c.Redirect(307, "http://"+host+"/malicious")
} else {
c.String(400, "Invalid host header")
}
})
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
// Function to validate the host header
func isValidHost(host string) bool {
// Add your whitelist of valid hosts here
validHosts := []string{"localhost:8080", "example.com"}
// Parse the host header
parsedHost, err := url.Parse(host)
if err != nil {
return false
}
// Check if the host header is in the whitelist
for _, validHost := range validHosts {
if parsedHost.Host == validHost {
return true
}
}
return false
}
The updated code includes a function
isValidHost
that validates the host header against a whitelist of valid hosts. This function is called before the redirect is performed. If the host header is not valid, the function returns a 400 status code with the message "Invalid host header".
The redirect method has been changed from HTTP 302 to HTTP 307. HTTP 307 is a secure redirect method that does not allow the HTTP method to change during the redirect. This can help prevent certain types of attacks.
The
isValidHost
function uses the
url.Parse
function from the
net/url
package to parse the host header. This function returns an error if the host header is not a valid URL, which helps to sanitize the input and remove any potentially malicious characters or sequences.
The whitelist of valid hosts is defined in the
validHosts
slice. This should be updated to include the actual valid hosts for your application. The function checks if the parsed host header is in this whitelist, and only allows the redirect to proceed if it is.
This approach helps to ensure that the host header cannot be manipulated to cause unintended redirects to malicious websites.