def testPolicy_compareTo_invalid(self): assert Policy.INVALID().compareTo(Policy.INVALID()) == (set([]), set([]), set([])) pol = Policy([PolicyTest.sampleDirective9]) assert pol.compareTo(Policy.INVALID()) == (set([]), set([]), set([])) assert Policy.INVALID().compareTo(pol) == (set([]), set([]), set([]))
def testPolicy_combinedPolicy_invalidPolicy(self): pol = Policy([ PolicyTest.sampleDirective1a, PolicyTest.sampleDirective2, PolicyTest.sampleDirective3 ]) assert pol.combinedPolicy(Policy.INVALID()) == Policy.INVALID() assert Policy.INVALID().combinedPolicy(pol) == Policy.INVALID()
def testLogEntry_generatePolicy_incomplete(self): logEntryNoReport = LogEntryTest.logEntryData.copy() del logEntryNoReport['csp-report'] logEntryNoPolicyType = LogEntryTest.logEntryData.copy() del logEntryNoPolicyType['policy-type'] assert LogEntry(logEntryNoReport).generatePolicy() == Policy.INVALID() assert LogEntry( logEntryNoPolicyType).generatePolicy() == Policy.INVALID()
def testReport_generatePolicy_missingReportField(self): reportNoViolated = Report({ "blocked-uri": ReportTest.sampleURI1a, "document-uri": ReportTest.sampleURI2 }) reportNoBlocked = Report({ "violated-directive": ReportTest.sampleDirective2a, "document-uri": ReportTest.sampleURI2 }) assert reportNoViolated.generatePolicy("regular") == Policy.INVALID() assert reportNoBlocked.generatePolicy("regular") == Policy.INVALID()
def testPolicy_matches_invalid(self): """An invalid policy matches nothing.""" selfURI = PolicyTest.sampleURI2 assert not Policy.INVALID().matches(PolicyTest.sampleURI1a, "script-src", selfURI) assert not Policy.INVALID().matches(URI.INVALID(), "script-src", selfURI) assert not Policy.INVALID().matches(URI.EMPTY(), "script-src", selfURI) assert not Policy.INVALID().matches(URI.INLINE(), "script-src", selfURI) assert not Policy.INVALID().matches(URI.EVAL(), "script-src", selfURI)
def testPolicy_eq(self): pol1a = Policy( (PolicyTest.sampleDirective1a, PolicyTest.sampleDirective2, PolicyTest.sampleDirective3)) pol1b = Policy( (PolicyTest.sampleDirective1b, PolicyTest.sampleDirective2, PolicyTest.sampleDirective3)) pol2 = Policy( (PolicyTest.sampleDirective2, PolicyTest.sampleDirective3)) assert Policy.INVALID() == Policy.INVALID() assert pol1a == pol1b assert hash(pol1a) == hash(pol1b) assert pol1a != pol2
def testPolicy_withoutPaths(self): withPaths = Policy([ PolicyTest.sampleDirective3, PolicyTest.sampleDirective5, PolicyTest.sampleDirective7 ]) withoutPaths = Policy([ PolicyTest.sampleDirective3, PolicyTest.sampleDirective5.withoutPaths(), PolicyTest.sampleDirective7 ]) assert withPaths.withoutPaths() == withoutPaths assert withoutPaths.withoutPaths() == withoutPaths assert Policy.INVALID().withoutPaths() == Policy.INVALID()
def generatePolicy(self): """ Generates a new policy that allows exactly the kind of event that caused the CSP violation report in this log entry (but nothing more). This assumes that (1) the violation report contains a specific violated-directive field (it may not be 'default-src'), and (2) that the log entry contains the type of the violation report ('regular', 'eval' or 'inline'). If any inconsistent log entries/reports are used to generate policies, the policies themselves will be inconsistent. The result of this method is a Policy. It is Policy.INVALID() if (1) the violated directive is missing, Directive.INVALID() or 'default-src', (2) if this log entry has none of the types 'regular', 'inline' or 'eval', (3) the 'blocked-uri' is URI.INVALID() or URI.EMPTY() in the 'regular' case. The result is a basic Policy containing one whitelisted resource (corresponding to the violated directive). In practice, it should not be used alone, but be combined with basic policies generated for other violations on the same web site. It should also be prepended with "default-src 'none'" to ensure that only the whitelisted resources are allowed. (The standard behaviour of CSP in absence of any default Directive is to assume "default-src *", which may not be the desired behaviour.) In particular, policies should be collected with CSP headers like these: Content-Security-Policy-Report-Only: default-src 'none'; script-src 'unsafe-eval' 'unsafe-inline'; object-src 'none'; style-src 'unsafe-inline'; img-src 'none'; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'none'; report-uri /csp.cgi?type=regular Content-Security-Policy-Report-Only: default-src *; script-src * 'unsafe-inline'; style-src * 'unsafe-inline'; report-uri /csp.cgi?type=eval Content-Security-Policy-Report-Only: default-src *; script-src * 'unsafe-eval'; style-src *; report-uri /csp.cgi?type=inline The results should also be filtered to ensure that only reports sent by fully compatible browsers are taken into account. """ if (self == LogEntry.INVALID() or 'policy-type' not in self or 'csp-report' not in self): return Policy.INVALID() return self['csp-report'].generatePolicy(self['policy-type'])
def testPolicy_isBasicPolicy(self): assert Policy.INVALID().isBasicPolicy() == False assert Policy([PolicyTest.sampleDirective6]).isBasicPolicy() == False assert Policy([PolicyTest.sampleDirective1a]).isBasicPolicy() == True assert Policy( [PolicyTest.sampleDirective2, PolicyTest.sampleDirective4]).isBasicPolicy() == False
def testReport_generatePolicy_fromInvalidDirectiveResult(self): reportDefaultSrc = Report({ "blocked-uri": ReportTest.sampleURI1a, "violated-directive": ReportTest.sampleDirective1a, "document-uri": ReportTest.sampleURI2 }) assert reportDefaultSrc.generatePolicy("regular") == Policy.INVALID()
def testPolicy_hasDefaultDirective(self): assert Policy.INVALID().hasDefaultDirective() == False assert Policy( [PolicyTest.sampleDirective2, PolicyTest.sampleDirective9]).hasDefaultDirective() == True assert Policy( [PolicyTest.sampleDirective5, PolicyTest.sampleDirective6]).hasDefaultDirective() == False
def testReport_generatePolicy_wrongDocumentURI(self): reportEmptyDocument = Report({ "blocked-uri": ReportTest.sampleURI1a, "violated-directive": ReportTest.sampleDirective1a, "document-uri": URI.EMPTY() }) assert reportEmptyDocument.generatePolicy( "regular") == Policy.INVALID()
def testPolicy_str_invalid(self): assert str(Policy.INVALID()) == "[invalid]"
def testReport_generatePolicy_invalid(self): assert Report.INVALID().generatePolicy("regular") == Policy.INVALID()
def testPolicy_asBasicPolicies_single(self): assert Policy.INVALID().asBasicPolicies() == set([]) assert Policy([PolicyTest.sampleDirective1a]).asBasicPolicies() == set( [Policy([PolicyTest.sampleDirective1a])])
def testPolicy_combinedPolicy_invalidDefaultSrcInOnePolicyOnly(self): pol1 = Policy([PolicyTest.sampleDirective3]) pol2 = Policy([PolicyTest.sampleDirective9]) assert pol1.combinedPolicy(pol2) == Policy.INVALID() assert pol2.combinedPolicy(pol1) == Policy.INVALID()
def testPolicy_combinedPolicy_invalidDefaultSrcAndOtherDirective(self): pol1 = Policy( [PolicyTest.sampleDirective1a, PolicyTest.sampleDirective3]) pol2 = Policy([PolicyTest.sampleDirective9]) assert pol1.combinedPolicy(pol2) == Policy.INVALID() assert pol2.combinedPolicy(pol1) == Policy.INVALID()
def testLogEntry_generatePolicy_invalid(self): assert LogEntry.INVALID().generatePolicy() == Policy.INVALID()
def testPolicyParser_parse_strict_onlyValidDirectives(self): """Ensures that a CSP policy does not parse in strict mode if it contains an invalid directive.""" policy = """img-src 'none'; script-src""" cspPolicy = PolicyParser(strict=True).parse(policy) assert cspPolicy == Policy.INVALID()