Man In The Middle in Gin with Basic Auth
Man In The Middle in Gin with Basic Auth — how this specific combination creates or exposes the vulnerability
Transport security is foundational when Basic Authentication is used, because the credentials are only base64‑encoded and not encrypted. In Gin, if an HTTP route is served without enforcing TLS, an on‑path attacker can intercept requests and decode the Authorization header. This scenario is commonly described as a Man In The Middle (MITM) risk in the context of Basic Auth.
Consider a Gin endpoint that reads the Authorization header manually. Without server‑side enforcement of HTTPS, credentials can be exposed in cleartext across networks, including potentially through proxies or compromised routers. Even if the client uses https://, missing server configuration (such as redirecting HTTP to HTTPS) can leave the channel open. The scanner’s checks include unauthenticated endpoint testing and encryption verification, which can surface routes served over plain HTTP alongside expectations for protected transport.
Because Basic Auth sends a static token per request, replay attacks are also possible if traffic is captured. An attacker who observes a valid Authorization header can reuse it until the token changes. This pairs poorly with weak routing or load‑balancer configurations that do not consistently enforce TLS termination. MiddleBrick’s encryption and transport checks highlight whether responses originate from endpoints that guarantee confidentiality in transit, which is especially important when credentials are not cryptographically protected by the protocol itself.
In practice, a Gin service that opts for Basic Auth should never rely on obscurity or network isolation. Developers must treat every non‑TLS path as observable and assume that credentials can be derived from traffic if MITM conditions exist. The scanner’s findings related to encryption and data exposure help identify routes that lack required protections, enabling teams to prioritize remediation focused on transport hardening before credentials are compromised.
Basic Auth-Specific Remediation in Gin — concrete code fixes
To mitigate MITM risks when using Basic Auth in Gin, enforce HTTPS for all routes and avoid handling credentials in cleartext on insecure channels. Below are concrete, working examples that demonstrate secure patterns.
1. Enforce HTTPS redirect in Gin
Ensure the server redirects HTTP requests to HTTPS. This reduces the window where credentials can traverse the network unencrypted.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.New()
// Redirect all HTTP traffic to HTTPS
r.Use(func(c *gin.Context) {
if c.Request.TLS == nil {
c.Redirect(http.StatusMovedPermanently, "https://" + c.Request.Host + c.Request.URL.Path)
c.Abort()
return
}
c.Next()
})
// Protected route example
r.GET("/secure", func(c *gin.Context) {
user, pass, ok := c.Request.BasicAuth()
if !ok || !validateCredentials(user, pass) {
c.Header("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "authenticated"})
})
http.ListenAndServe(":80", r)
}
2. Serve only HTTPS with TLS configuration
Configure the Gin server to listen securely and provide certificates directly. This is the primary defense against MITM when Basic Auth is required.
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func validateCredentials(user, pass string) bool {
// Replace with secure credential validation (e.g., constant-time compare)
return user == "admin" && pass == "correct-hashed-password"
}
func main() {
r := gin.Default()
r.GET("/api/data", func(c *gin.Context) {
user, pass, ok := c.Request.BasicAuth()
if !ok || !validateCredentials(user, pass) {
c.Header("WWW-Authenticate", `Basic realm="api", charset="UTF-8"`)
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}
c.JSON(http.StatusOK, gin.H{"data": "secure response"})
})
// Use ListenAndServeTLS to enforce HTTPS
err := r.RunTLS(":443", "cert.pem", "key.pem")
if err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
3. Middleware approach for centralized enforcement
Encapsulate authentication and transport checks in middleware to keep routes consistent and reduce the risk of accidental cleartext exposure.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func TLSRedirect() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.TLS == nil {
c.Redirect(http.StatusMovedPermanently, "https://" + c.Request.Host + c.Request.URL.RequestURI())
c.Abort()
}
c.Next()
}
}
func BasicAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
user, pass, ok := c.Request.BasicAuth()
if !ok || !validateCredentials(user, pass) {
c.Header("WWW-Authenticate", `Basic realm="api", charset="UTF-8"`)
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
c.Next()
}
}
func main() {
r := gin.New()
r.Use(TLSRedirect())
r.Use(BasicAuthMiddleware())
r.GET("/resource", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"ok": true})
})
// Secure server entry point
http.ListenAndServeTLS(":443", "cert.pem", "key.pem", r)
}
Remediation guidance
- Always redirect HTTP to HTTPS to prevent credentials from traversing cleartext networks.
- Use TLS termination at the server or load balancer and ensure certificates are valid and managed.
- Avoid logging Authorization headers and handle credentials with care to prevent accidental exposure.
- Combine Basic Auth with additional protections such as short token lifetimes where feasible.