01
Capture the request contract, not the secret URL
Record the intended method, object key, signed header names, and expiration. Treat a real presigned URL as a temporary capability and keep it out of public logs or screenshots. A copied link that was decoded, shortened, or rebuilt can change the signed input.
In our test, the signer authorized put_object with ContentType=text/plain. Recomputing the same request matched its signature. Changing only the HTTP method or that signed header value changed the computed signature, independently of any bucket policy.
02
Generate a PUT URL for the intended object
Use a client configured for the bucket’s verified Region and credentials authorized for the upload. This example selects a named profile for local use; a deployed signer should use its intended workload identity instead.
The key is an example placeholder. Choose a unique test object because a successful upload to an existing key can replace that object. Generating a URL locally does not itself prove that its signer has effective upload permission.
import boto3
from botocore.config import Config
s3 = boto3.Session(profile_name="work").client(
"s3", region_name="eu-west-1", config=Config(signature_version="s3v4")
)
url = s3.generate_presigned_url(
"put_object",
Params={"Bucket": "YOUR_BUCKET", "Key": "tests/UNIQUE-report.txt",
"ContentType": "text/plain"},
ExpiresIn=300,
)
# Deliver the URL privately to the intended uploader.03
Send the matching request
A URL intended for PUT is not interchangeable with opening it as a GET in the address bar. Likewise, a form upload can have a different method, body format, or Content-Type from the signed direct-object upload.
For this contract, send the file with PUT and text/plain. Substitute the privately supplied URL without reconstructing its query parameters. Do not add a different content type merely because a browser or HTTP library guessed one.
# PRESIGNED_URL was supplied privately; do not log it.
curl --fail --request PUT --upload-file ./report.txt \
--header 'Content-Type: text/plain' "$PRESIGNED_URL"04
Check the remaining signature inputs
If method and signed headers match, inspect the exact object path, URL encoding, signing Region, clock, and expiration. Temporary signing credentials can expire before a URL’s requested lifetime. Use the service’s recorded error rather than reducing every 403 to the same cause.
Browser CORS errors are another layer: a command-line upload may succeed while a browser is blocked by cross-origin policy. Diagnose that case from its preflight and response headers after establishing whether S3 accepted the signed request.
05
Verify the authorized operation separately
In a permitted test environment, upload to the unique key and confirm the expected bytes or application result. Effective signer permissions and policies still apply; matching a mathematical signature cannot grant an operation the signer is not allowed to perform.
Our local result establishes which request changes affect the signature. A real deployment still needs an actual authorized upload check, and any test object should be handled through that environment’s normal cleanup policy.
Sınırları bil
Tested offline with Boto3 1.42.97 SigV4 presigning and signature recomputation using synthetic credentials. Matching PUT/text/plain produced the same signature; GET or a different signed Content-Type did not. No S3 upload, IAM authorization, or browser CORS flow was tested.
Kaynaklar ve ileri okuma
CoreTrailKit tarafından hazırlanan teknik yayın.
Bütün yazıları keşfet