fix: V-002 security vulnerability

Automated security fix generated by Orbis Security AI
This commit is contained in:
orbisai0security 2026-04-22 12:25:19 +05:30
parent d3ffc99852
commit 4b95dc09e5
2 changed files with 57 additions and 0 deletions

12
auth.go
View File

@ -52,6 +52,12 @@ func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
realm = "Basic realm=" + strconv.Quote(realm)
pairs := processAccounts(accounts)
return func(c *Context) {
// Enforce HTTPS: Basic Auth credentials are Base64-encoded, not
// encrypted, and must not be transmitted over plain HTTP.
if c.Request.TLS == nil && c.GetHeader("X-Forwarded-Proto") != "https" {
c.AbortWithStatus(http.StatusForbidden)
return
}
// Search user in the slice of allowed credentials
user, found := pairs.searchCredential(c.requestHeader("Authorization"))
if !found {
@ -102,6 +108,12 @@ func BasicAuthForProxy(accounts Accounts, realm string) HandlerFunc {
realm = "Basic realm=" + strconv.Quote(realm)
pairs := processAccounts(accounts)
return func(c *Context) {
// Enforce HTTPS: Basic Auth credentials are Base64-encoded, not
// encrypted, and must not be transmitted over plain HTTP.
if c.Request.TLS == nil && c.GetHeader("X-Forwarded-Proto") != "https" {
c.AbortWithStatus(http.StatusForbidden)
return
}
proxyUser, found := pairs.searchCredential(c.requestHeader("Proxy-Authorization"))
if !found {
// Credentials doesn't match, we return 407 and abort handlers chain.

View File

@ -92,6 +92,7 @@ func TestBasicAuthSucceed(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/login", nil)
req.Header.Set("Authorization", authorizationHeader("admin", "password"))
req.Header.Set("X-Forwarded-Proto", "https")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
@ -111,6 +112,7 @@ func TestBasicAuth401(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/login", nil)
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
req.Header.Set("X-Forwarded-Proto", "https")
router.ServeHTTP(w, req)
assert.False(t, called)
@ -118,6 +120,26 @@ func TestBasicAuth401(t *testing.T) {
assert.Equal(t, "Basic realm=\"Authorization Required\"", w.Header().Get("WWW-Authenticate"))
}
func TestBasicAuth403OverHTTP(t *testing.T) {
called := false
accounts := Accounts{"foo": "bar"}
router := New()
router.Use(BasicAuth(accounts))
router.GET("/login", func(c *Context) {
called = true
c.String(http.StatusOK, c.MustGet(AuthUserKey).(string))
})
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/login", nil)
req.Header.Set("Authorization", authorizationHeader("foo", "bar"))
// No X-Forwarded-Proto and no TLS — must be rejected before credentials are checked.
router.ServeHTTP(w, req)
assert.False(t, called)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestBasicAuth401WithCustomRealm(t *testing.T) {
called := false
accounts := Accounts{"foo": "bar"}
@ -131,6 +153,7 @@ func TestBasicAuth401WithCustomRealm(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/login", nil)
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
req.Header.Set("X-Forwarded-Proto", "https")
router.ServeHTTP(w, req)
assert.False(t, called)
@ -149,6 +172,7 @@ func TestBasicAuthForProxySucceed(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("Proxy-Authorization", authorizationHeader("admin", "password"))
req.Header.Set("X-Forwarded-Proto", "https")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
@ -168,9 +192,30 @@ func TestBasicAuthForProxy407(t *testing.T) {
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
req.Header.Set("X-Forwarded-Proto", "https")
router.ServeHTTP(w, req)
assert.False(t, called)
assert.Equal(t, http.StatusProxyAuthRequired, w.Code)
assert.Equal(t, "Basic realm=\"Proxy Authorization Required\"", w.Header().Get("Proxy-Authenticate"))
}
func TestBasicAuthForProxy403OverHTTP(t *testing.T) {
called := false
accounts := Accounts{"foo": "bar"}
router := New()
router.Use(BasicAuthForProxy(accounts, ""))
router.Any("/*proxyPath", func(c *Context) {
called = true
c.String(http.StatusOK, c.MustGet(AuthProxyUserKey).(string))
})
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("Proxy-Authorization", authorizationHeader("foo", "bar"))
// No X-Forwarded-Proto and no TLS — must be rejected before credentials are checked.
router.ServeHTTP(w, req)
assert.False(t, called)
assert.Equal(t, http.StatusForbidden, w.Code)
}