mirror of
https://github.com/rustfs/rustfs.git
synced 2026-09-22 10:33:25 +00:00
fix(auth): reject unsigned x-amz headers on header-signed SigV4 requests (#7796)
* fix(auth): reject unsigned x-amz headers on header-signed SigV4 requests A SigV4 request authenticated with an Authorization header only binds the headers named in its SignedHeaders list, but RustFS acted on every x-amz-* header that arrived, so a replayed header-signed PutObject carrying an unsigned x-amz-copy-source became a CopyObject run as the signer that could copy any object the signer can read (GHSA-xm99-m3gq-83g8). The presigned form was already closed by GHSA-g8w9-qw9q-fghr. reject_unsigned_amz_headers_on_sigv4_request now guards S3Access::check and S3Router::check_access: every SigV4 signed-header list the request carries must cover every x-amz-* header, the Authorization header is parsed with the verifier's own s3s-sigv4 parser and compared case-insensitively, the algorithm token is pinned to AWS4-HMAC-SHA256 because the upstream header path accepts any token, and the exempt set mirrors the upstream s3s fix (x-amz-content-sha256, x-amz-decoded-content-length, x-amz-trailer, x-amz-checksum-algorithm) plus x-amz-cf-id. Adds ghsa_xm99 unit, router and e2e regressions, raises the security smoke floor to 28, and records the advisory in docs/testing/security-regressions.md and CHANGELOG.md. * chore(deps): switch s3s and s3s-sigv4 to crates.io 0.16.0 * fix(server): enforce the SigV4 header guard ahead of s3s dispatch s3s 0.16 verifies the claimed algorithm as the first step of its own signature flow, so a request whose Authorization header swaps the AWS4-HMAC-SHA256 token was answered with 501 NotImplemented before RustFS's access layer could rule on the unsigned x-amz-copy-source (GHSA-xm99-m3gq-83g8). Add the SigV4HeaderGuardLayer as the innermost external stack layer, running reject_unsigned_amz_headers_on_sigv4_request in front of s3s and serializing its rejections as the same AccessDenied S3 error document the access layer produces. --------- Co-authored-by: Hauser <housemecn@gmail.com>
This commit is contained in:
@@ -18,6 +18,7 @@ Every fixed RustFS GitHub Security Advisory maps to at least one named regressio
|
||||
| [GHSA-6r96-hmgc-726c](https://github.com/rustfs/rustfs/security/advisories/GHSA-6r96-hmgc-726c) | Request headers must not populate server-derived IAM condition keys (`userid`, `groups`, `jwt:`/`ldap:` claims) | fixed, GHSA private-fork merge | `ghsa_6r96_identity_condition_keys_ignore_spoofed_headers`, `ghsa_6r96_claim_condition_keys_ignore_spoofed_headers`, and `test_request_headers_still_reach_conditions`, which keeps the reserved set from growing too broad (`rustfs/src/auth.rs`) | unit |
|
||||
| [GHSA-x298-9x87-fvjq](https://github.com/rustfs/rustfs/security/advisories/GHSA-x298-9x87-fvjq) | Anonymous ListObjectVersions -> `s3:ListBucket` fallback must reach the same public-access gates as a direct grant | fixed, GHSA private-fork merge | `ghsa_x298_anonymous_list_object_versions_denied_when_restrict_public_buckets_enabled` (`crates/e2e_test/src/anonymous_access_test.rs`); asserts 200 before the public-access block is applied so it proves the gate, not a broken fallback | e2e (`e2e-smoke`) |
|
||||
| [GHSA-g8w9-qw9q-fghr](https://github.com/rustfs/rustfs/security/advisories/GHSA-g8w9-qw9q-fghr) | A SigV4 presigned request must reject `x-amz-*` headers missing from `X-Amz-SignedHeaders` (tags, storage class, ACL, metadata, redirect, Object Lock, SSE) instead of applying them | this fix | `ghsa_g8w9_presigned_request_rejects_unsigned_x_amz_headers`, `ghsa_g8w9_presigned_request_accepts_signed_or_exempt_x_amz_headers`, `ghsa_g8w9_check_ignores_header_signed_sigv2_and_anonymous_requests` (`rustfs/src/auth.rs`); `ghsa_g8w9_check_access_rejects_unsigned_amz_header_on_presigned_custom_route` for routes that bypass `S3Access::check` (`rustfs/src/admin/router.rs`); `ghsa_g8w9_presigned_put_rejects_unsigned_x_amz_headers`, `ghsa_g8w9_presigned_get_rejects_unsigned_x_amz_headers`, `ghsa_g8w9_presigned_put_rejects_unsigned_copy_source`, plus the signed-tagging control `ghsa_g8w9_presigned_put_accepts_signed_x_amz_headers` and the unsigned-`Content-Type` boundary control `ghsa_g8w9_presigned_put_still_accepts_unsigned_non_amz_headers` (`crates/e2e_test/src/presigned_negative_test.rs`) | unit; e2e (`e2e-smoke`) |
|
||||
| GHSA-xm99-m3gq-83g8 | A header-signed SigV4 request must reject `x-amz-*` headers missing from its `SignedHeaders` (an unsigned `x-amz-copy-source` turned a replayed PutObject into a cross-bucket CopyObject), and a non-`AWS4-HMAC-SHA256` algorithm token must not route around that check | this fix | `ghsa_xm99_header_sigv4_rejects_unsigned_x_amz_headers`, `ghsa_xm99_header_sigv4_accepts_signed_or_exempt_x_amz_headers`, `ghsa_xm99_header_sigv4_rejects_unsupported_algorithm_token`, `ghsa_xm99_header_and_query_signatures_cannot_widen_each_other`, `ghsa_xm99_check_ignores_sigv2_jwt_and_anonymous_requests` (`rustfs/src/auth.rs`); `ghsa_xm99_check_access_rejects_unsigned_amz_header_on_header_signed_custom_route` for routes that bypass `S3Access::check` (`rustfs/src/admin/router.rs`); `ghsa_xm99_header_sigv4_rejects_unsigned_copy_source`, which also asserts the destination bytes survive, plus the signed-copy control `ghsa_xm99_header_sigv4_accepts_signed_copy_source` (`crates/e2e_test/src/negative_sigv4_test.rs`) | unit; e2e (`e2e-smoke`) |
|
||||
| [GHSA-g3vq-vv42-f647](https://github.com/rustfs/rustfs/security/advisories/GHSA-g3vq-vv42-f647) | FTPS `MKD` must clear the `s3:CreateBucket` authorization boundary before reaching the backend | fixed, GHSA private-fork merge | `ghsa_g3vq_mkd_denied_before_reaching_backend` (`crates/protocols/src/ftps/driver.rs`); primes `create_bucket` to succeed so the assertion distinguishes "denied at authorization" from "backend refused" | unit (`ftps` feature) |
|
||||
|
||||
## Where these run
|
||||
|
||||
Reference in New Issue
Block a user