I burned several hours on a Tencent Cloud COS signature error, and the cause was so small it felt absurd. I was moving my blog's image hosting. I didn't want to keep using Bilibili for that, mainly because I didn't want to wake up one day and find the images gone. So I started looking into Tencent Cloud Object Storage with signed requests.
Tencent provides an online signing tool for COS. It has an optional field called HttpParameters. The point is to let you add extra parameters to the signed request, which can be useful for identity markers or similar. The catch is that the tool does not reorder those parameters. Whatever order you type in is the order used for signing.
For example, if you enter renji=hacker&chibang=dabing, the tool signs it in that order: renji first, chibang second. It does not sort by dictionary order, despite what you might expect. The resulting signature is not the same as the signature for chibang=dabing&renji=hacker.
That would be manageable if COS verified the signature in the same order. It does not. On the verification side, COS forces the parameters into lexicographical order before checking the signature. So the signing tool can produce a signature over unsorted parameters, while COS reconstructs the string to sign with sorted parameters. Even if the signature was generated correctly from what you typed, the verifier sees a different parameter string, and the request fails.
I got stuck on this for hours. It felt like two parts of the same system were working against each other. You really have to wonder how that design made it out the door.
The practical warning is short: when using HttpParameters, sort the parameter names lexicographically yourself. If you don't, you can generate a signature that is technically correct for the order you entered, and COS will still reject it because its side reorders the parameters before verification.
The error log I got looked like this:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The Signature you specified is invalid.</Message>
<StringToSign>sha1 1782919296;1782922896
8fca24aeaa82174638d101081b3c7b697635711a</StringToSign>
<FormatString>get /renji.txt chibang=dabing&renji=hacker</FormatString>
<Resource>/renji.txt</Resource>
<RequestId>NmE0NTMwYTFfODdkNGZlMDlfMjczYTBfMTExNWMyNjk=</RequestId>
<TraceId>OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTQyYWVlY2MwZTk2MDVmZDQ3MmI2Y2I4ZmI5ZmM4ODFjNWUzMTJiNDQ5MjAyZTI4YmY3YzA0ODBkODE4ZjJmYmU=</TraceId>
</Error>
That was it. A correct-looking signature, a SignatureDoesNotMatch error, and an ordering mismatch buried in an optional field. The fix is to sort the parameter names before signing, because COS will not do it for you on the signing side.