mirror of
https://github.com/project-zot/zot.git
synced 2026-06-15 11:37:56 +08:00
fix(security): limit API key creation body to 4 KiB (INPUT-2) (#3978)
Wrap req.Body with http.MaxBytesReader before io.ReadAll in CreateAPIKey. Requests with bodies larger than MaxAPIKeyBodySize (4 KiB) now return HTTP 413 instead of buffering arbitrary data. Add the MaxAPIKeyBodySize constant, update the Swagger @Failure annotation to document 413, and add a unit test. Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>
This commit is contained in:
committed by
GitHub
parent
35c29b95e4
commit
eadc9b65ed
@@ -22,7 +22,9 @@ const (
|
||||
MaxManifestDigestQueryTags = (8192 - 2048) / (len("tag=") + 128 + 1)
|
||||
// MaxManifestBodySize is the maximum number of bytes accepted for a manifest PUT request body.
|
||||
// OCI manifest JSON is always small metadata; 4 MiB is well above any realistic manifest.
|
||||
MaxManifestBodySize = 4 * 1024 * 1024
|
||||
MaxManifestBodySize = 4 * 1024 * 1024
|
||||
// MaxAPIKeyBodySize is the maximum number of bytes accepted for an API-key creation request body.
|
||||
MaxAPIKeyBodySize = 4 * 1024
|
||||
BlobUploadUUID = "Blob-Upload-UUID"
|
||||
DefaultMediaType = "application/json"
|
||||
BinaryMediaType = "application/octet-stream"
|
||||
|
||||
+9
-3
@@ -2342,15 +2342,21 @@ func (rh *RouteHandler) GetAPIKeys(resp http.ResponseWriter, req *http.Request)
|
||||
// @Success 201 {string} string "created"
|
||||
// @Failure 400 {string} string "bad request"
|
||||
// @Failure 401 {string} string "unauthorized"
|
||||
// @Failure 413 {string} string "request entity too large"
|
||||
// @Failure 500 {string} string "internal server error"
|
||||
// @Router /zot/auth/apikey [post].
|
||||
func (rh *RouteHandler) CreateAPIKey(resp http.ResponseWriter, req *http.Request) {
|
||||
var payload APIKeyPayload
|
||||
|
||||
body, err := io.ReadAll(req.Body)
|
||||
body, err := io.ReadAll(http.MaxBytesReader(resp, req.Body, constants.MaxAPIKeyBodySize))
|
||||
if err != nil {
|
||||
rh.c.Log.Error().Msg("failed to read request body")
|
||||
resp.WriteHeader(http.StatusInternalServerError)
|
||||
var mbe *http.MaxBytesError
|
||||
if errors.As(err, &mbe) {
|
||||
resp.WriteHeader(http.StatusRequestEntityTooLarge)
|
||||
} else {
|
||||
rh.c.Log.Error().Msg("failed to read request body")
|
||||
resp.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1604,6 +1604,22 @@ func TestRoutes(t *testing.T) {
|
||||
So(resp.StatusCode, ShouldEqual, http.StatusInternalServerError)
|
||||
})
|
||||
|
||||
Convey("CreateAPIKey body exceeds MaxAPIKeyBodySize returns 413", func() {
|
||||
userAc := reqCtx.NewUserAccessControl()
|
||||
userAc.SetUsername("test")
|
||||
ctx := userAc.DeriveContext(context.Background())
|
||||
|
||||
oversized := make([]byte, constants.MaxAPIKeyBodySize+1)
|
||||
request, _ := http.NewRequestWithContext(ctx, http.MethodPost, baseURL, bytes.NewReader(oversized))
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
rthdlr.CreateAPIKey(response, request)
|
||||
|
||||
resp := response.Result()
|
||||
defer resp.Body.Close()
|
||||
So(resp.StatusCode, ShouldEqual, http.StatusRequestEntityTooLarge)
|
||||
})
|
||||
|
||||
Convey("CreateAPIKey bad request body", func() {
|
||||
userAc := reqCtx.NewUserAccessControl()
|
||||
userAc.SetUsername("test")
|
||||
|
||||
@@ -1099,6 +1099,12 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"413": {
|
||||
"description": "request entity too large",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
|
||||
@@ -1091,6 +1091,12 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"413": {
|
||||
"description": "request entity too large",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "internal server error",
|
||||
"schema": {
|
||||
|
||||
@@ -1004,6 +1004,10 @@ paths:
|
||||
description: unauthorized
|
||||
schema:
|
||||
type: string
|
||||
"413":
|
||||
description: request entity too large
|
||||
schema:
|
||||
type: string
|
||||
"500":
|
||||
description: internal server error
|
||||
schema:
|
||||
|
||||
Reference in New Issue
Block a user