Deprecate query string auth tokens (#28390)
## Changes - Add deprecation warning to `Token` and `AccessToken` authentication methods in swagger. - Add deprecation warning header to API response. Example: ``` HTTP/1.1 200 OK ... Warning: token and access_token API authentication is deprecated ... ``` - Add setting `DISABLE_QUERY_AUTH_TOKEN` to reject query string auth tokens entirely. Default is `false` ## Next steps - `DISABLE_QUERY_AUTH_TOKEN` should be true in a subsequent release and the methods should be removed in swagger - `DISABLE_QUERY_AUTH_TOKEN` should be removed and the implementation of the auth methods in question should be removed ## Open questions - Should there be further changes to the swagger documentation? Deprecation is not yet supported for security definitions (coming in [OpenAPI Spec version 3.2.0](https://github.com/OAI/OpenAPI-Specification/issues/2506)) - Should the API router logger sanitize urls that use `token` or `access_token`? (This is obviously an insufficient solution on its own) --------- Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
parent
baea205675
commit
4e879fed90
|
@ -492,6 +492,11 @@ INTERNAL_TOKEN=
|
||||||
;; Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations.
|
;; Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations.
|
||||||
;; This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
|
;; This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
|
||||||
;SUCCESSFUL_TOKENS_CACHE_SIZE = 20
|
;SUCCESSFUL_TOKENS_CACHE_SIZE = 20
|
||||||
|
;;
|
||||||
|
;; Reject API tokens sent in URL query string (Accept Header-based API tokens only). This avoids security vulnerabilities
|
||||||
|
;; stemming from cached/logged plain-text API tokens.
|
||||||
|
;; In future releases, this will become the default behavior
|
||||||
|
;DISABLE_QUERY_AUTH_TOKEN = false
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
|
@ -34,6 +34,7 @@ var (
|
||||||
PasswordHashAlgo string
|
PasswordHashAlgo string
|
||||||
PasswordCheckPwn bool
|
PasswordCheckPwn bool
|
||||||
SuccessfulTokensCacheSize int
|
SuccessfulTokensCacheSize int
|
||||||
|
DisableQueryAuthToken bool
|
||||||
CSRFCookieName = "_csrf"
|
CSRFCookieName = "_csrf"
|
||||||
CSRFCookieHTTPOnly = true
|
CSRFCookieHTTPOnly = true
|
||||||
)
|
)
|
||||||
|
@ -157,4 +158,11 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
|
||||||
PasswordComplexity = append(PasswordComplexity, name)
|
PasswordComplexity = append(PasswordComplexity, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: default value should be true in future releases
|
||||||
|
DisableQueryAuthToken = sec.Key("DISABLE_QUERY_AUTH_TOKEN").MustBool(false)
|
||||||
|
|
||||||
|
if !DisableQueryAuthToken {
|
||||||
|
log.Warn("Enabling Query API Auth tokens is not recommended. DISABLE_QUERY_AUTH_TOKEN will default to true in gitea 1.23 and will be removed in gitea 1.24.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,12 @@
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: token
|
// name: token
|
||||||
// in: query
|
// in: query
|
||||||
|
// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
|
||||||
// AccessToken:
|
// AccessToken:
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: access_token
|
// name: access_token
|
||||||
// in: query
|
// in: query
|
||||||
|
// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
|
||||||
// AuthorizationHeaderToken:
|
// AuthorizationHeaderToken:
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: Authorization
|
// name: Authorization
|
||||||
|
@ -788,6 +790,13 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.APIC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for and warn against deprecated authentication options
|
||||||
|
func checkDeprecatedAuthMethods(ctx *context.APIContext) {
|
||||||
|
if ctx.FormString("token") != "" || ctx.FormString("access_token") != "" {
|
||||||
|
ctx.Resp.Header().Set("Warning", "token and access_token API authentication is deprecated and will be removed in gitea 1.23. Please use AuthorizationHeaderToken instead. Existing queries will continue to work but without authorization.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Routes registers all v1 APIs routes to web application.
|
// Routes registers all v1 APIs routes to web application.
|
||||||
func Routes() *web.Route {
|
func Routes() *web.Route {
|
||||||
m := web.NewRoute()
|
m := web.NewRoute()
|
||||||
|
@ -806,6 +815,8 @@ func Routes() *web.Route {
|
||||||
}
|
}
|
||||||
m.Use(context.APIContexter())
|
m.Use(context.APIContexter())
|
||||||
|
|
||||||
|
m.Use(checkDeprecatedAuthMethods)
|
||||||
|
|
||||||
// Get user from session if logged in.
|
// Get user from session if logged in.
|
||||||
m.Use(apiAuth(buildAuthGroup()))
|
m.Use(apiAuth(buildAuthGroup()))
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/web/middleware"
|
"code.gitea.io/gitea/modules/web/middleware"
|
||||||
"code.gitea.io/gitea/services/auth/source/oauth2"
|
"code.gitea.io/gitea/services/auth/source/oauth2"
|
||||||
|
@ -62,6 +63,7 @@ func (o *OAuth2) Name() string {
|
||||||
// representing whether the token exists or not
|
// representing whether the token exists or not
|
||||||
func parseToken(req *http.Request) (string, bool) {
|
func parseToken(req *http.Request) (string, bool) {
|
||||||
_ = req.ParseForm()
|
_ = req.ParseForm()
|
||||||
|
if !setting.DisableQueryAuthToken {
|
||||||
// Check token.
|
// Check token.
|
||||||
if token := req.Form.Get("token"); token != "" {
|
if token := req.Form.Get("token"); token != "" {
|
||||||
return token, true
|
return token, true
|
||||||
|
@ -70,6 +72,10 @@ func parseToken(req *http.Request) (string, bool) {
|
||||||
if token := req.Form.Get("access_token"); token != "" {
|
if token := req.Form.Get("access_token"); token != "" {
|
||||||
return token, true
|
return token, true
|
||||||
}
|
}
|
||||||
|
} else if req.Form.Get("token") != "" || req.Form.Get("access_token") != "" {
|
||||||
|
log.Warn("API token sent in query string but DISABLE_QUERY_AUTH_TOKEN=true")
|
||||||
|
}
|
||||||
|
|
||||||
// check header token
|
// check header token
|
||||||
if auHead := req.Header.Get("Authorization"); auHead != "" {
|
if auHead := req.Header.Get("Authorization"); auHead != "" {
|
||||||
auths := strings.Fields(auHead)
|
auths := strings.Fields(auHead)
|
||||||
|
|
2
templates/swagger/v1_json.tmpl
generated
2
templates/swagger/v1_json.tmpl
generated
|
@ -24046,6 +24046,7 @@
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
"AccessToken": {
|
"AccessToken": {
|
||||||
|
"description": "This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.",
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"name": "access_token",
|
"name": "access_token",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
|
@ -24078,6 +24079,7 @@
|
||||||
"in": "header"
|
"in": "header"
|
||||||
},
|
},
|
||||||
"Token": {
|
"Token": {
|
||||||
|
"description": "This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.",
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"name": "token",
|
"name": "token",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
|
|
Loading…
Reference in a new issue