mirror of
https://github.com/project-zot/zot.git
synced 2026-06-17 21:17:58 +08:00
fix(security): enhance timeout configurations and body size limits fo… (#3984)
* fix(security): enhance timeout configurations and body size limits for HTTP requests Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(tests): refactor backend result handling in proxyHTTPRequest test Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): preserve ContentLength in proxied requests to prevent server hang Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): preserve explicit zero-length request bodies in proxyHTTPRequest fix(tests): add test for normalizedTimeout function to ensure default fallback Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): prevent default HTTP timeout values from being set unless explicitly configured Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): refactor timeout handling to use explicit checks for nil and non-positive values Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(tests): add wait_for_event_count function to ensure expected event generation Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): improve timeout handling and update error responses for large requests Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): enhance HTTP timeout handling with explicit accessors and default values Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): increase default API key body size and timeout values for improved performance Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): unify timeout handling by replacing specific read/write timeouts with a single default timeout Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): consolidate HTTP timeout accessors and enhance timeout handling Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> * fix(security): simplify HTTP timeout accessors and set default values for read/write timeouts Co-authored-by: Copilot <copilot@github.com> Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> --------- Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com> Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
committed by
GitHub
parent
8282aef12b
commit
934b22d124
@@ -82,12 +82,18 @@ type ImageTrust struct {
|
||||
// @Param requestBody body string true "Public key content"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Failure 400 {string} string "bad request"
|
||||
// @Failure 413 {string} string "request entity too large"
|
||||
// @Failure 500 {string} string "internal server error"
|
||||
func (trust *ImageTrust) HandleCosignPublicKeyUpload(response http.ResponseWriter, request *http.Request) {
|
||||
body, err := io.ReadAll(request.Body)
|
||||
body, err := io.ReadAll(http.MaxBytesReader(response, request.Body, constants.MaxImageTrustBodySize))
|
||||
if err != nil {
|
||||
trust.Log.Error().Err(err).Str("component", "image-trust").Msg("failed to read cosign key body")
|
||||
response.WriteHeader(http.StatusInternalServerError)
|
||||
var mbe *http.MaxBytesError
|
||||
if errors.As(err, &mbe) {
|
||||
response.WriteHeader(http.StatusRequestEntityTooLarge)
|
||||
} else {
|
||||
trust.Log.Error().Err(err).Str("component", "image-trust").Msg("failed to read cosign key body")
|
||||
response.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -117,6 +123,7 @@ func (trust *ImageTrust) HandleCosignPublicKeyUpload(response http.ResponseWrite
|
||||
// @Param requestBody body string true "Certificate content"
|
||||
// @Success 200 {string} string "ok"
|
||||
// @Failure 400 {string} string "bad request"
|
||||
// @Failure 413 {string} string "request entity too large"
|
||||
// @Failure 500 {string} string "internal server error"
|
||||
func (trust *ImageTrust) HandleNotationCertificateUpload(response http.ResponseWriter, request *http.Request) {
|
||||
var truststoreType string
|
||||
@@ -127,10 +134,15 @@ func (trust *ImageTrust) HandleNotationCertificateUpload(response http.ResponseW
|
||||
truststoreType = "ca" // default value of "truststoreType" query param
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(request.Body)
|
||||
body, err := io.ReadAll(http.MaxBytesReader(response, request.Body, constants.MaxImageTrustBodySize))
|
||||
if err != nil {
|
||||
trust.Log.Error().Err(err).Str("component", "image-trust").Msg("failed to read notation certificate body")
|
||||
response.WriteHeader(http.StatusInternalServerError)
|
||||
var mbe *http.MaxBytesError
|
||||
if errors.As(err, &mbe) {
|
||||
response.WriteHeader(http.StatusRequestEntityTooLarge)
|
||||
} else {
|
||||
trust.Log.Error().Err(err).Str("component", "image-trust").Msg("failed to read notation certificate body")
|
||||
response.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package extensions_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -56,7 +57,8 @@ func TestSignatureHandlers(t *testing.T) {
|
||||
}
|
||||
|
||||
Convey("Test error handling when Cosign handler reads the request body", t, func() {
|
||||
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPost, "baseURL", errReader(0))
|
||||
request, err := http.NewRequestWithContext(context.TODO(), http.MethodPost, "http://example.com", errReader(0))
|
||||
So(err, ShouldBeNil)
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
trust.HandleCosignPublicKeyUpload(response, request)
|
||||
@@ -67,7 +69,8 @@ func TestSignatureHandlers(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Test error handling when Notation handler reads the request body", t, func() {
|
||||
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPost, "baseURL", errReader(0))
|
||||
request, err := http.NewRequestWithContext(context.TODO(), http.MethodPost, "http://example.com", errReader(0))
|
||||
So(err, ShouldBeNil)
|
||||
query := request.URL.Query()
|
||||
request.URL.RawQuery = query.Encode()
|
||||
|
||||
@@ -78,6 +81,34 @@ func TestSignatureHandlers(t *testing.T) {
|
||||
defer resp.Body.Close()
|
||||
So(resp.StatusCode, ShouldEqual, http.StatusInternalServerError)
|
||||
})
|
||||
|
||||
Convey("Test cosign upload body over max size returns 413", t, func() {
|
||||
overSizedBody := make([]byte, constants.MaxImageTrustBodySize+1)
|
||||
request, err := http.NewRequestWithContext(context.TODO(), http.MethodPost,
|
||||
"http://example.com", bytes.NewReader(overSizedBody))
|
||||
So(err, ShouldBeNil)
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
trust.HandleCosignPublicKeyUpload(response, request)
|
||||
|
||||
resp := response.Result()
|
||||
defer resp.Body.Close()
|
||||
So(resp.StatusCode, ShouldEqual, http.StatusRequestEntityTooLarge)
|
||||
})
|
||||
|
||||
Convey("Test notation upload body over max size returns 413", t, func() {
|
||||
overSizedBody := make([]byte, constants.MaxImageTrustBodySize+1)
|
||||
request, err := http.NewRequestWithContext(context.TODO(), http.MethodPost,
|
||||
"http://example.com", bytes.NewReader(overSizedBody))
|
||||
So(err, ShouldBeNil)
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
trust.HandleNotationCertificateUpload(response, request)
|
||||
|
||||
resp := response.Result()
|
||||
defer resp.Body.Close()
|
||||
So(resp.StatusCode, ShouldEqual, http.StatusRequestEntityTooLarge)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSignaturesAllowedMethodsHeader(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user