4

I'm currently trying to implement an Express application using the Serverless framework on API Gateway + Lambda. Everything worked as expected until I started introducing request signing on our end. The signing works in a way that it signs the complete URL including the query string using a secret token. Unfortunately it seems like either API Gateway or Cloudfront are re-sorting the query string alphabetically which leads to the checksum generated on our side to be different from the one the client generated.

What our Express server sees:

https://example.com/endpoint?build_number=1&platform=ios

What the client was sending:

https://example.com/endpoint?platform=ios &build_number=1

As you can see the query parameters got re-sorted alphabetically which is no behaviour I would expect.

Any idea?

1 Answer 1

5

I'd suggest that your algorithm is destined to give you issues, because the query string is a set of key/value pairs with no intrinsic ordering.

There should not be an expectation that it will pass through any particular system in any particular order. The same is true of request headers. Some libraries that build HTTP requests store query string parameters in an intermediate dictionary/hash structure, so even absent the issue you see here (which I suspect to be API Gateway, since CloudFront claims to preserve the ordering), which is arguably a sub-optimal design since ?color=red&size=large is (again, arguably, but pretty compellingly-so) exactly the same thing as ?size=large&color=red.

My guess would be that API Gateway may be optimizing its ability to perform caching (which does not actually use the CloudFront cache -- it has its own implementation) by canonicalizing the query string ordering.

But, as I suggest above, your algorithm should require a binary, lexical sort (case sensitive, rather than "alphabetical" which might be assumed to be case insensitive) of the query parameters on the sending end and the same thing again on the receiving end.

This seems like unnecessary complexity, but this is almost certainly why the various AWS signing algorithms require the query string (and header, for the same reason) keys and values be sorted before signing -- because you simply can't rely on client libraries, proxies, or other entities to handle them consistently.

Sign up to request clarification or add additional context in comments.

2 Comments

Perfect answer.
I get the spirit of the answer. I find it annoying that they don’t at least give you a context property, or some way of getting the original query string. In my case, I’m writing a mock api which hashes the request based on attributes, including the query string. So I now have to either go back and re-hash everything to sort the query string params as api gateway does, or calculate every permutation to find the right hash.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.