diff --git a/middleware/basic_auth.go b/middleware/basic_auth.go index 4a46098e3..f92a318e7 100644 --- a/middleware/basic_auth.go +++ b/middleware/basic_auth.go @@ -78,7 +78,7 @@ func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc { auth := c.Request().Header.Get(echo.HeaderAuthorization) l := len(basic) - if len(auth) > l+1 && strings.EqualFold(auth[:l], basic) { + if len(auth) > l+1 && auth[l] == ' ' && strings.EqualFold(auth[:l], basic) { // Invalid base64 shouldn't be treated as error // instead should be treated as invalid client input b, err := base64.StdEncoding.DecodeString(auth[l+1:]) diff --git a/middleware/basic_auth_test.go b/middleware/basic_auth_test.go index 2d3192615..9f9fc5744 100644 --- a/middleware/basic_auth_test.go +++ b/middleware/basic_auth_test.go @@ -118,6 +118,27 @@ func TestBasicAuth(t *testing.T) { } } +func TestBasicAuthRejectsInvalidSchemeBoundary(t *testing.T) { + e := echo.New() + validatorCalled := false + e.Use(BasicAuth(func(user, password string, c echo.Context) (bool, error) { + validatorCalled = true + return user == "joe" && password == "secret", nil + })) + e.GET("/", func(c echo.Context) error { + return c.NoContent(http.StatusNoContent) + }) + + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.Header.Set(echo.HeaderAuthorization, "BasicX"+base64.StdEncoding.EncodeToString([]byte("joe:secret"))) + rec := httptest.NewRecorder() + e.ServeHTTP(rec, req) + + assert.Equal(t, http.StatusUnauthorized, rec.Code) + assert.Equal(t, basic+` realm="Restricted"`, rec.Header().Get(echo.HeaderWWWAuthenticate)) + assert.False(t, validatorCalled) +} + func TestBasicAuthRealm(t *testing.T) { e := echo.New() mockValidator := func(u, p string, c echo.Context) (bool, error) {