Refactor internal routers (partial backport, auth token const time comparing) (#32473) (#32479)

Partially backport #32473. LFS related changes are not in 1.22, so skip
them.

1. Ignore non-existing repos during migrations
2. Improve ReadBatchLine's comment
3. Use `X-Gitea-Internal-Auth` header for internal API calls and make
the comparing constant time (it wasn't a serous problem because in a
real world it's nearly impossible to timing-attack the token, but indeed
security related and good to fix and backport)
4. Fix route mock nil check
This commit is contained in:
wxiaoguang
2024-11-13 10:26:37 +08:00
committed by GitHub
parent 26437a03b0
commit ef339713c2
5 changed files with 28 additions and 15 deletions
+10 -8
View File
@@ -5,6 +5,7 @@
package private
import (
"crypto/subtle"
"net/http"
"strings"
@@ -18,22 +19,23 @@ import (
chi_middleware "github.com/go-chi/chi/v5/middleware"
)
// CheckInternalToken check internal token is set
func CheckInternalToken(next http.Handler) http.Handler {
func authInternal(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
tokens := req.Header.Get("Authorization")
fields := strings.SplitN(tokens, " ", 2)
if setting.InternalToken == "" {
log.Warn(`The INTERNAL_TOKEN setting is missing from the configuration file: %q, internal API can't work.`, setting.CustomConf)
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
return
}
if len(fields) != 2 || fields[0] != "Bearer" || fields[1] != setting.InternalToken {
tokens := req.Header.Get("X-Gitea-Internal-Auth") // TODO: use something like JWT or HMAC to avoid passing the token in the clear
after, found := strings.CutPrefix(tokens, "Bearer ")
authSucceeded := found && subtle.ConstantTimeCompare([]byte(after), []byte(setting.InternalToken)) == 1
if !authSucceeded {
log.Debug("Forbidden attempt to access internal url: Authorization header: %s", tokens)
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
} else {
next.ServeHTTP(w, req)
return
}
next.ServeHTTP(w, req)
})
}
@@ -51,7 +53,7 @@ func bind[T any](_ T) any {
func Routes() *web.Route {
r := web.NewRoute()
r.Use(context.PrivateContexter())
r.Use(CheckInternalToken)
r.Use(authInternal)
// Log the real ip address of the request from SSH is really helpful for diagnosing sometimes.
// Since internal API will be sent only from Gitea sub commands and it's under control (checked by InternalToken), we can trust the headers.
r.Use(chi_middleware.RealIP)