def test_preloaded(self): result = is_hpkp_preloaded('apis.google.com') self.assertTrue(result['pinned']) self.assertTrue(result['includeSubDomainsForPinning']) result = is_hpkp_preloaded('foo.apis.google.com') self.assertTrue(result['pinned']) self.assertTrue(result['includeSubDomainsForPinning']) # uses include_subdomains_for_pinning result = is_hpkp_preloaded('dropboxstatic.com') self.assertTrue(result['pinned']) self.assertTrue(result['includeSubDomainsForPinning'])
def test_preloaded(self): result = is_hpkp_preloaded('apis.google.com') self.assertTrue(result['pinned']) self.assertTrue(result['includeSubDomainsForPinning']) result = is_hpkp_preloaded('foo.apis.google.com') self.assertTrue(result['pinned']) self.assertTrue(result['includeSubDomainsForPinning']) # uses include_subdomains_for_pinning result = is_hpkp_preloaded('dropboxstatic.com') self.assertTrue(result['pinned']) self.assertTrue(result['includeSubDomainsForPinning'])
def test_preloaded(self): result = is_hpkp_preloaded("apis.google.com") self.assertTrue(result["pinned"]) self.assertTrue(result["includeSubDomainsForPinning"]) result = is_hpkp_preloaded("foo.apis.google.com") self.assertTrue(result["pinned"]) self.assertTrue(result["includeSubDomainsForPinning"]) # uses include_subdomains_for_pinning result = is_hpkp_preloaded("dropboxstatic.com") self.assertTrue(result["pinned"]) self.assertTrue(result["includeSubDomainsForPinning"]) # this domain is manually pinned result = is_hpkp_preloaded("aus4.mozilla.org") self.assertTrue(result["pinned"]) self.assertTrue(result["includeSubDomainsForPinning"])
def public_key_pinning(reqs: dict, expectation='hpkp-not-implemented') -> dict: """ :param reqs: dictionary containing all the request and response objects :param expectation: test expectation; possible results: hpkp-not-implemented-no-https hpkp-not-implemented hpkp-implemented-max-age-less-than-fifteen-days hpkp-implemented-max-age-at-least-fifteen-days hpkp-preloaded hpkp-header-invalid hpkp-invalid-cert :return: dictionary with: data: the raw HPKP header includesubdomains: whether the includeSubDomains directive is set max-age: what the max num-pins: the number of pins expectation: test expectation pass: whether the site's configuration met its expectation result: short string describing the result of the test """ FIFTEEN_DAYS = 1296000 output = { 'data': None, 'expectation': expectation, 'includeSubDomains': False, 'max-age': None, 'numPins': None, 'pass': True, 'preloaded': False, 'result': 'hpkp-not-implemented', } response = reqs['responses']['https'] # If there's no HTTPS, we can't have HPKP if response is None: output['result'] = 'hpkp-not-implemented-no-https' # Can't have HPKP without a valid certificate chain elif not response.verified: output['result'] = 'hpkp-invalid-cert' elif 'Public-Key-Pins' in response.headers: output['data'] = response.headers['Public-Key-Pins'][ 0:2048] # code against malicious headers try: pkp = [i.lower().strip() for i in output['data'].split(';')] pins = [] for parameter in pkp: if parameter.startswith('max-age='): output['max-age'] = int(parameter[8:128]) # defense elif parameter.startswith( 'pin-sha256=') and parameter not in pins: pins.append(parameter) elif parameter == 'includesubdomains': output['includeSubDomains'] = True output['numPins'] = len(pins) # You must set a max-age with HPKP if output['max-age']: if output['max-age'] < FIFTEEN_DAYS: output[ 'result'] = 'hpkp-implemented-max-age-less-than-fifteen-days' else: output[ 'result'] = 'hpkp-implemented-max-age-at-least-fifteen-days' # You must have at least two pins with HPKP and set max-age if not output['max-age'] or len(pins) < 2: raise ValueError except: output['result'] = 'hpkp-header-invalid' output['pass'] = False # If they're in the preloaded list, this overrides most anything else if response is not None: preloaded = is_hpkp_preloaded(urlparse(response.url).netloc) if preloaded: output['result'] = 'hpkp-preloaded' output['includeSubDomains'] = preloaded[ 'includeSubDomainsForPinning'] output['preloaded'] = True # No need to check pass/fail here, the only way to fail is to have an invalid header return output
def test_not_preloaded(self): result = is_hpkp_preloaded("totallyfakehostname.insertsuperduperfakedomainhere.wtftld") self.assertFalse(result)
def public_key_pinning(reqs: dict, expectation='hpkp-not-implemented') -> dict: """ :param reqs: dictionary containing all the request and response objects :param expectation: test expectation; possible results: hpkp-not-implemented-no-https hpkp-not-implemented hpkp-implemented-max-age-less-than-fifteen-days hpkp-implemented-max-age-at-least-fifteen-days hpkp-preloaded hpkp-header-invalid :return: dictionary with: data: the raw HPKP header includesubdomains: whether the includeSubDomains directive is set max-age: what the max num-pins: the number of pins expectation: test expectation pass: whether the site's configuration met its expectation result: short string describing the result of the test """ FIFTEEN_DAYS = 1296000 output = { 'data': None, 'expectation': expectation, 'includeSubDomains': False, 'max-age': None, 'numPins': None, 'pass': True, 'preloaded': False, 'result': 'hpkp-not-implemented', } response = reqs['responses']['https'] # If there's no HTTPS, we can't have HPKP if response is None: output['result'] = 'hpkp-not-implemented-no-https' elif 'Public-Key-Pins' in response.headers: output['data'] = response.headers['Public-Key-Pins'][0:2048] # code against malicious headers try: pkp = [i.lower().strip() for i in output['data'].split(';')] pins = [] for parameter in pkp: if parameter.startswith('max-age='): output['max-age'] = int(parameter[8:128]) # defense elif parameter.startswith('pin-sha256=') and parameter not in pins: pins.append(parameter) elif parameter == 'includesubdomains': output['includeSubDomains'] = True output['numPins'] = len(pins) # You must set a max-age with HPKP if output['max-age']: if output['max-age'] < FIFTEEN_DAYS: output['result'] = 'hpkp-implemented-max-age-less-than-fifteen-days' else: output['result'] = 'hpkp-implemented-max-age-at-least-fifteen-days' # You must have at least two pins with HPKP and set max-age if not output['max-age'] or len(pins) < 2: raise ValueError except: output['result'] = 'hpkp-header-invalid' output['pass'] = False # If they're in the preloaded list, this overrides most anything else if response is not None: preloaded = is_hpkp_preloaded(urlparse(response.url).netloc) if preloaded: output['result'] = 'hpkp-preloaded' output['includeSubDomains'] = preloaded['includeSubDomainsForPinning'] output['preloaded'] = True # No need to check pass/fail here, the only way to fail is to have an invalid header return output
def test_not_preloaded(self): result = is_hpkp_preloaded('totallyfakehostname.insertsuperduperfakedomainhere.wtftld') self.assertFalse(result)