def check(self): csp = self.csp if not csp or not csp.parsedstring: return [] findings = [] directivesToCheck = csp.getEffectiveDirectives( csp.DIRECTIVES_CAUSING_XSS) for directive in directivesToCheck: values = [] if directive in csp.parsedstring: values = csp[directive] for value in values: url = Util.getSchemeFreeUrl(value) if '*' in url and len(url) == 1: findings.append( Finding( csp.headerkey, FindingType.PLAIN_WILDCARD, directive.value + ' should not allow \'*\' as source. This may enable execution of malicious JavaScript.', FindingSeverity.HIGH, directive, value)) return findings
def checkIP(self, directive, directiveValues, findings): csp = self.csp for value in directiveValues: url = '//' + Util.getSchemeFreeUrl(value) host = urlparse(url).netloc ip = None validip = True try: ip = ipaddress.ip_address(u'' + host) except ValueError: validip = False if validip: ipString = str(ip) + '' if '127.0.0.1' in ipString: findings.append( Finding( csp.headerkey, FindingType.IP_SOURCE, directive.value + ' directive allows localhost as source. Please make sure to remove this in production environments.', FindingSeverity.INFO, directive, value)) else: findings.append( Finding( csp.headerkey, FindingType.IP_SOURCE, directive.value + ' directive has an IP-Address as source: ' + ipString + ' (will be ignored by browsers!). ', FindingSeverity.INFO, directive, value))
def check(self, headers, opt_options=dict()): policy = self.getfeaturepolicy(headers) if not policy or not policy.parsedstring: return [] findings = [] directivesToCheck = policy.getEffectiveDirectives() for directive in directivesToCheck: values = policy.getEffectiveValues(directive) for value in values: url = Util.getSchemeFreeUrl(value) if url and str(FeaturePolicyKeyword.STAR) in url and len( url ) == 1 and directive != FeaturePolicyDirective.PICTURE_IN_PICTURE: findings.append( Finding( policy.headerkey, FindingType.PLAIN_WILDCARD, directive.value + ' should not allow \'*\' as source. It enables the current page and nesting contexts, such as iframes, to use the feature. It may be better to disable and explicitly tell the iframe which feature is allowed.', FindingSeverity.LOW, directive, value)) return findings
def check(self, opt_options=dict()): csp = self.csp if not csp: return [] findings = [] angular = [] jsonp = [] jsonpeval = [] if 'bypasses' not in opt_options.keys(): bypasses = [] else: bypasses = opt_options['bypasses'] directive = csp.getEffectiveDirective(csp.directive.OBJECT_SRC) objectSrcValues = [] try: objectSrcValues = csp[directive] except KeyError: objectSrcValues = [] if csp.directive.PLUGIN_TYPES in csp.parsedstring: pluginTypes = csp[csp.directive.PLUGIN_TYPES] else: pluginTypes = None if pluginTypes and not 'application/x-shockwave-flash' in pluginTypes: return [] for value in objectSrcValues: if value == csp.keyword.NONE: return [] url = '//' + Util.getSchemeFreeUrl(value) flashBypass = Util.matchWildcardUrls(url, bypasses) if (flashBypass): findings.append( Finding( csp.headerkey, FindingType.OBJECT_WHITELIST_BYPASS, flashBypass.netloc + ' is known to host Flash files which allow to bypass this CSP.', FindingSeverity.HIGH, directive, value)) elif (directive == csp.directive.OBJECT_SRC): findings.append( Finding(csp.headerkey, FindingType.OBJECT_WHITELIST_BYPASS, 'Can you restrict object-src to \'none\' only?', FindingSeverity.MEDIUM_MAYBE, directive, value)) return findings
def check(self, opt_options=dict()): csp = self.csp if not csp: return [] findings = [] cdn = [] if 'cdn' not in opt_options.keys(): cdn = [] elif 'cdn' in opt_options.keys(): cdn = opt_options['cdn'] effectiveScriptSrcDirective = csp.getEffectiveDirective( csp.directive.SCRIPT_SRC) scriptSrcValues = [] try: scriptSrcValues = csp[effectiveScriptSrcDirective] except KeyError: scriptSrcValues = [] for value in scriptSrcValues: if value.startswith('\''): continue if Util.isUrlScheme(value) or value.find('.') == -1: continue url = '//' + Util.getSchemeFreeUrl(value) cdnbypass = Util.matchWildcardUrls(url, cdn) if cdnbypass: bypassDomain = '' bypassUrl = '//' + cdnbypass.netloc + cdnbypass.path bypassDomain = cdnbypass.netloc findings.append( Finding( csp.headerkey, FindingType.SCRIPT_WHITELIST_BYPASS, bypassDomain + ' is known to host many libraries which allow to bypass this CSP. Do not whitelist all scripts of a CDN.', FindingSeverity.HIGH, effectiveScriptSrcDirective, value)) return findings
def test_getSchemeFreeUrlNone(self): self.assertEqual(Util.getSchemeFreeUrl(None), None)
def test_getSchemeFreeUrlCapitals(self): self.assertEqual(Util.getSchemeFreeUrl('HTTPS://www.synopsys.com'), 'www.synopsys.com')
def test_getSchemeFreeUrlValid(self): self.assertEqual(Util.getSchemeFreeUrl('http://www.synopsys.com'), 'www.synopsys.com')
def check(self, opt_options=dict()): csp = self.csp if not csp: return [] findings = [] angular = [] jsonp = [] jsonpeval = [] if 'angular' not in opt_options.keys(): angular = [] elif 'angular' in opt_options.keys(): angular = opt_options['angular'] if 'jsonp' not in opt_options.keys(): jsonp = [] if 'jsonp' in opt_options.keys(): jsonp = opt_options['jsonp'] if 'jsonpeval' not in opt_options.keys(): jsonpeval = [] if 'jsonpeval' in opt_options.keys(): jsonpeval = opt_options['jsonpeval'] effectiveScriptSrcDirective = csp.getEffectiveDirective( csp.directive.SCRIPT_SRC) scriptSrcValues = [] try: scriptSrcValues = csp[effectiveScriptSrcDirective] except KeyError: scriptSrcValues = [] for value in scriptSrcValues: if value == csp.keyword.SELF or value == str(csp.keyword.SELF): findings.append( Finding( csp.headerkey, FindingType.SCRIPT_WHITELIST_BYPASS, '\'self\' can be problematic if you host JSONP, Angular or user uploaded files.', FindingSeverity.MEDIUM_MAYBE, effectiveScriptSrcDirective, value)) continue if value.startswith('\''): continue if Util.isUrlScheme(value) or value.find('.') == -1: continue url = '//' + Util.getSchemeFreeUrl(value) angularBypass = Util.matchWildcardUrls(url, angular) jsonpBypass = Util.matchWildcardUrls(url, jsonp) if jsonpBypass: bypassUrl = '//' + jsonpBypass.netloc + jsonpBypass.path evalRequired = jsonpBypass.netloc in jsonpeval evalPresent = csp.keyword.UNSAFE_EVAL in scriptSrcValues if evalRequired and not evalPresent: jsonpBypass = None if jsonpBypass or angularBypass: bypassDomain = '' bypassTxt = '' if jsonpBypass: bypassDomain = jsonpBypass.netloc bypassTxt = ' JSONP endpoints' if angularBypass: bypassDomain = angularBypass.netloc if not bypassTxt: bypassTxt += '' else: bypassTxt += ' and' bypassTxt += ' Angular libraries' findings.append( Finding( csp.headerkey, FindingType.SCRIPT_WHITELIST_BYPASS, bypassDomain + ' is known to host' + bypassTxt + ' which allow to bypass this CSP.', FindingSeverity.HIGH, effectiveScriptSrcDirective, value)) else: findings.append( Finding( csp.headerkey, FindingType.SCRIPT_WHITELIST_BYPASS, 'No bypass found; make sure that this URL doesn\'t serve JSONP replies or Angular libraries.', FindingSeverity.MEDIUM_MAYBE, effectiveScriptSrcDirective, value)) return findings