0

I'm attempting to pull JSON data from an API and struggling to nail down the source of my problems. Currently I get accurate data if message = "" but so far any non-empty query parameters return a 403 error. The API documentation asks for parameters to be formatted as "customerCode=XXX" and I've been able to produce valid queries in the API Sandbox. I assume the problem is somewhere in the getSignature function, but I've rewritten it a few ways and .encode() or bytes() gives me the same result. If the code looks coherent and it's a syntax error on my end I can reach out to the support team. Again, when message is an empty string I get valid results back so I'm puzzled. Error occurs on all tested Report pages with multiple different query parameters tested per page. Relevant import functions are not pasted here but are included in the code.

#Current hash
def getSignature(message):
    hashed = hmac.new(key, message.encode('utf-8') , hashlib.sha256)
    return base64.b64encode(hashed.digest())


#Header per API specs
def getData(report, message):
    headers = {
        'Content-Type' : 'application/json',
        'Accept' : 'application/json',
        'api-auth-id' : api_id,
        'api-auth-signature' : getSignature(message)                
    }

    data = requests.get(url + report, headers=headers)
    data = data.json()

    return data

1 Answers1

0

EDIT: I just noticed that message is only being used for the signature, and is not being included in the request. I think you probably need something like data = requests.get(url + report, data=message, headers=headers).

Old, almost certainly incorrect theory is below:

Since it works for an empty message, my guess is that it has to do with the byte encoding of the message. The utf-16 or utf-32 encodings of the empty message will be the same as the utf-8, but they will differ for non-empty messages.

So perhaps try message.encode('utf-16') or message.encode('utf-32')? The API docs should describe this detail of how auth is done.

Is it possible to link to the docs for the API, or is it internal?

mgsloan
  • 3,095
  • 18
  • 20
  • Looks like both utf-16 and utf-32 return 403 errors even on an empty string. – Ben Courts Mar 01 '18 at 23:21
  • Hmm, and `data=message` also doesn't fix it? Curious. I don't have time right now to look into it in detail, but skimming that, the fact that `GetSignature` takes "args" causes some alarm bells. Gotta make sure the input of the signature function is correct – mgsloan Mar 01 '18 at 23:43
  • From my reading of the docs the query is only supposed to be submitted as part of the hash then pulled out server side. I don't think it gets submitted as a non-encoded string in the style of data=message. – Ben Courts Mar 02 '18 at 19:28
  • Yeah, it's quite possible that the utf-8 encoded messages should be given to the `data` param. The message _must_ be provided in the request. It is impossible for the server to pull the message out of the hash. Hashes are small summaries for potentially large amounts of data. By signing the hash of the message, you're proving that you have the private key and authenticating only this specific message. Technically, an attacker could attempt to find a hash collision, but that's extraordinarily difficult for sha-256. – mgsloan Mar 02 '18 at 22:13