-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
What's missing?
Hi there. I'm trying to implement the server side of AWS SigV4 Authentication algorithm.
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html
With other frameworks I'd create a middleware which can calculate the required value, and allows or denies the requests accordingly.
With rocket it seems to be quite difficult.
Here's a nice summary of the Algorithm used by AWS:
https://towardsaws.com/aws-sigv4-in-3-mins-c324d20f19cf
So all I have to do is collect url, some headers and the payload,
#Create a Canonical Request
CanonicalRequest =
HTTPRequestMethod + '\n' +
CanonicalURI + '\n' +
CanonicalQueryString + '\n' +
CanonicalHeaders + '\n' +
SignedHeaders + '\n' +
HexEncode(Hash(RequestPayload))
and then shove that through HMAC a few times in different configuration, together with a secret which both the server and the client know.
The resulting string is then compared with the Authorization
header, to be equal.
Here's an example with requwests:
https://github.com/aws-samples/sigv4-signing-examples/blob/main/no-sdk/rust/src/main.rs
So, my idea is to use a Request Guard,
#[rocket::async_trait]
impl<'r> FromRequest<'r> for AuthCheckPassed {
Unfortunately, those can't access the body, which is needed in the signing process (RequestPlayload
above).
I thought to combine it with an Request fairing (https://docs.rs/rocket/latest/rocket/fairing/trait.Fairing.html#method.on_request), which could then inspect the body, and calculate the Header to compare with.
It would then use request-local state (https://rocket.rs/guide/v0.5/state/#request-local-state) to store it, and have a FormRequest pick it back up again and do the final check against the Authorization
header (or check a comparison result boolean), as the Fairing itself can't return a "permission denied" response.
While this is cumbersome and inconvenient, it sounds doable, unless you realize not even the Fairings have full access to the data.
The maximum upload part size is however allowed to be 5GiB (see AWS docs: https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html).
In the code for Data.peek
, however the length is hardcoded to 512 bytes, which is not even close.
Using something like Limits::new().limit("json", ByteUnit::Megabyte(1000 * 1024 * 1024))
will not change that.
Unfortunately, data is of type data: &mut Data<'_>
instead of data: Data<'_>
, making the open()
function to get a buffer unavailable (can't move).
TL;DR: The Problem
With the current rocket, it is impossible to implement the industry standard Amazon Webservices SigV4 Authentication algorithm as laid out above.
Ideal Solution
No response
Why can't this be implemented outside of Rocket?
Auth and inspecting the request should be part of the webserver (rocket). Having a reverse proxy just for what would be a simple middleware in other frameworks makes no sense.
Are there workarounds usable today?
Not really, no.
The closest thing is using Data.peek
and hoping the request will never be more than 512 bytes (uuuh bad idea, it will be)
Alternative Solutions
Use a different framework.
Additional Context
This is related to the closed #700, which has a response similar to "Q: how do I do that? A: You don't, your use case is stupid.", which is not helpful (good old stack overflow vibes).
System Checks
- I do not believe that this feature can or should be implemented outside of Rocket.
- I was unable to find a previous request for this feature.