From c13173ed7557bae0274e8689517e77d533de1c3b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 23 Aug 2019 12:20:20 +0100 Subject: [PATCH] Mitigate replay attacks --- httpsig.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/httpsig.py b/httpsig.py index 48c364131..cf22d1af6 100644 --- a/httpsig.py +++ b/httpsig.py @@ -17,6 +17,7 @@ from requests.auth import AuthBase import base64 import json from time import gmtime, strftime +import datetime from pprint import pprint def messageContentDigest(messageBodyJsonStr: str) -> str: @@ -59,9 +60,9 @@ def signPostHeaders(dateStr: str,privateKeyPem: str, \ signedHeaderText = '' for headerKey in signedHeaderKeys: signedHeaderText += f'{headerKey}: {headers[headerKey]}\n' - print(f'*********************signing: headerKey: {headerKey}: {headers[headerKey]}') + #print(f'*********************signing: headerKey: {headerKey}: {headers[headerKey]}') signedHeaderText = signedHeaderText.strip() - print('******************************Send: signedHeaderText: '+signedHeaderText) + #print('******************************Send: signedHeaderText: '+signedHeaderText) headerDigest = SHA256.new(signedHeaderText.encode('ascii')) # Sign the digest @@ -103,12 +104,12 @@ def createSignedHeader(privateKeyPem: str,nickname: str, \ path,httpPrefix,None) else: bodyDigest=messageContentDigest(messageBodyJsonStr) - print('***************************Send (request-target): post '+path) - print('***************************Send host: '+headerDomain) - print('***************************Send date: '+dateStr) - print('***************************Send digest: '+bodyDigest) - print('***************************Send Content-type: '+contentType) - print('***************************Send messageBodyJsonStr: '+messageBodyJsonStr) + #print('***************************Send (request-target): post '+path) + #print('***************************Send host: '+headerDomain) + #print('***************************Send date: '+dateStr) + #print('***************************Send digest: '+bodyDigest) + #print('***************************Send Content-type: '+contentType) + #print('***************************Send messageBodyJsonStr: '+messageBodyJsonStr) headers = {'(request-target)': f'post {path}','host': headerDomain,'date': dateStr,'digest': f'SHA-256={bodyDigest}','content-type': contentType} signatureHeader = \ signPostHeaders(dateStr,privateKeyPem,nickname, \ @@ -130,6 +131,7 @@ def verifyPostHeaders(httpPrefix: str,publicKeyPem: str,headers: dict, \ GETmethod - GET or POST messageBodyJsonStr - the received request body (used for digest) """ + if GETmethod: method='GET' else: @@ -162,6 +164,16 @@ def verifyPostHeaders(httpPrefix: str,publicKeyPem: str,headers: dict, \ #print('***************************Verify digest: SHA-256='+bodyDigest) #print('***************************Verify messageBodyJsonStr: '+messageBodyJsonStr) else: + if signedHeader=='date': + # mitigate replay attacks + currDate=datetime.datetime.utcnow() + signedDate=datetime.datetime.strptime(headers[signedHeader],"%a, %d %b %Y %H:%M:%S %Z") + # 12 hours tollerance + if (currDate-signedDate).seconds > 43200: + print('WARN: Header signed too long ago: '+headers[signedHeader]) + print(str((currDate-signedDate).seconds/(60*60))+' hours') + return False + if headers.get(signedHeader): #print('***************************Verify '+signedHeader+': '+headers[signedHeader]) signedHeaderList.append(