Change API protocol to fix json normalization

A dictionnary's order is not deterministic (eg. when switching python
versions), thus the previous protocol would often fail to authenticate a
legitimate request.
This commit is contained in:
Théophile Bastian 2017-10-16 20:02:36 +02:00
parent f01c0b5594
commit 2264b0886f
2 changed files with 17 additions and 8 deletions

View file

@ -33,7 +33,8 @@ def sendReq(url):
mac = hmac.new(key.encode('utf-8'), mac = hmac.new(key.encode('utf-8'),
msg=str(int(time)).encode('utf-8'), msg=str(int(time)).encode('utf-8'),
digestmod=hashlib.sha256) digestmod=hashlib.sha256)
mac.update(json.dumps(payload).encode('utf-8')) payload_enc = json.dumps(payload)
mac.update(payload_enc.encode('utf-8'))
auth = { auth = {
'keyId': keyId, 'keyId': keyId,
@ -43,7 +44,7 @@ def sendReq(url):
return { return {
'auth': auth, 'auth': auth,
'req': payload, 'req': payload_enc,
} }
def decorator(fct): def decorator(fct):

View file

@ -20,8 +20,7 @@ def authentify(data, payload):
except models.ApiKey.DoesNotExist: except models.ApiKey.DoesNotExist:
return response.HttpResponseForbidden('Bad authentication') return response.HttpResponseForbidden('Bad authentication')
normPayload = json.dumps(payload) if not key.isCorrect(data['timestamp'], data['hmac'], payload):
if not key.isCorrect(data['timestamp'], data['hmac'], normPayload):
return response.HttpResponseForbidden('Bad authentication') return response.HttpResponseForbidden('Bad authentication')
@ -30,22 +29,31 @@ def apiView(required=[]):
@csrf_exempt @csrf_exempt
def wrap(request, *args, **kwargs): def wrap(request, *args, **kwargs):
try: try:
data = json.loads(request.body) data = json.loads(request.body.decode('utf-8'))
except json.decoder.JSONDecoreError: except TypeError:
return response.HttpResponseBadRequest("Bad packet format")
except json.decoder.JSONDecodeError:
return response.HttpResponseBadRequest("Bad json") return response.HttpResponseBadRequest("Bad json")
try: try:
authData = data['auth'] authData = data['auth']
reqData = data['req'] reqDataOrig = data['req']
except KeyError: except KeyError:
return response.HttpResponseBadRequest("Bad request format") return response.HttpResponseBadRequest("Bad request format")
try:
reqData = json.loads(reqDataOrig)
except TypeError:
return response.HttpResponseBadRequest("Bad packet format")
except json.decoder.JSONDecodeError:
return response.HttpResponseBadRequest("Bad inner json")
for field in required: for field in required:
if field not in reqData: if field not in reqData:
return response.HttpResponseBadRequest( return response.HttpResponseBadRequest(
"Missing field {}".format(field)) "Missing field {}".format(field))
authVal = authentify(authData, reqData) authVal = authentify(authData, reqDataOrig)
if authVal is not None: if authVal is not None:
return authVal return authVal