def testDirective_eq(self): srcExpr1 = URISourceExpression("http", "seclab.nu", "*", None) srcExpr2 = URISourceExpression("https", "seclab.nu", 443, "/") directive1a = Directive("object-src", [srcExpr1, srcExpr2]) directive1b = Directive("object-src", [srcExpr2, srcExpr1]) directive2 = Directive("frame-src", [srcExpr1, srcExpr2]) directive3 = Directive("object-src", [srcExpr2]) directive4a = Directive("script-src", (SourceExpression.UNSAFE_INLINE(), )) directive4b = Directive("script-src", (SourceExpression("unsafe-inline"), )) assert directive1a == directive1b assert hash(directive1a) == hash(directive1b) assert directive1a != directive2 assert directive1a != directive3 assert directive2 != directive3 assert directive4a == directive4b assert hash(directive4a) == hash(directive4b) assert Directive.INVALID() == Directive.INVALID() assert Directive.INVALID() not in (directive1a, directive1b, directive2, directive3) assert Directive.INLINE_STYLE_BASE_RESTRICTION() not in (directive1a, directive1b, directive2, directive3)
def test_EvalInlineSourceExpression_eq(self): assert SourceExpression.UNSAFE_EVAL() == SourceExpression.UNSAFE_EVAL() assert hash(SourceExpression.UNSAFE_EVAL()) \ == hash(SourceExpression.UNSAFE_EVAL()) assert SourceExpression.UNSAFE_INLINE( ) == SourceExpression.UNSAFE_INLINE() assert hash(SourceExpression.UNSAFE_INLINE()) \ == hash(SourceExpression.UNSAFE_INLINE()) assert SourceExpression.UNSAFE_INLINE( ) != SourceExpression.UNSAFE_EVAL()
def testDirectiveParser_parse_standard(self): assert DirectiveParser(strict=True).parse("default-src https: 'unsafe-inline' 'unsafe-eval'") \ == Directive("default-src", [URISourceExpression("https", None, None, None), SourceExpression.UNSAFE_INLINE(), SourceExpression.UNSAFE_EVAL()]) assert DirectiveParser(strict=True).parse("default-src 'self'") \ == Directive("default-src", [SelfSourceExpression.SELF()]) assert DirectiveParser(strict=True).parse("img-src *") \ == Directive("img-src", [URISourceExpression(None, "*", None, None)]) assert DirectiveParser(strict=True).parse("object-src media1.example.com media2.example.com *.cdn.example.com") \ == Directive("object-src", [URISourceExpression(None, "media1.example.com", None, None), URISourceExpression(None, "media2.example.com", None, None), URISourceExpression(None, "*.cdn.example.com", None, None)])
def test_EvalInlineSourceExpression_match(self): """The source expressions 'unsafe-inline' and 'unsafe-eval' do not match any URI.""" srcExprEval = SourceExpression.UNSAFE_EVAL() srcExprInline = SourceExpression.UNSAFE_INLINE() selfURI = SourceExpressionTest.uri_chromeExtension assert not srcExprEval.matches(SourceExpressionTest.uri_empty, selfURI) assert not srcExprInline.matches(SourceExpressionTest.uri_empty, selfURI) assert not srcExprEval.matches(URI.INVALID(), selfURI) assert not srcExprInline.matches(URI.INVALID(), selfURI) assert srcExprInline.matches(URI.INLINE(), selfURI) assert not srcExprInline.matches(URI.EVAL(), selfURI) assert not srcExprEval.matches(URI.INLINE(), selfURI) assert srcExprEval.matches(URI.EVAL(), selfURI)
class PolicyDataReaderTest(unittest.TestCase): samplePolicy = Policy([ Directive("default-src", ()), Directive("style-src", [SourceExpression.UNSAFE_INLINE()]), Directive("img-src", [URISourceExpression(None, "seclab.nu", "*", None)]) ]) @pytest.fixture(autouse=True) def initdir(self, tmpdir): tmpdir.chdir() def setUp(self): self.fileIn = PolicyDataReader(True) self.filename = "policystorage.dat" self.fileOut = DataWriter(self.filename) def testReportCreation(self): """Writes a LogEntry and loads it back as an object.""" self.fileOut.storeAll([PolicyDataReaderTest.samplePolicy]) self.fileOut.close() dataOut = self.fileIn.loadAll(self.filename) assert len(dataOut) == 1 assert PolicyDataReaderTest.samplePolicy in dataOut
def test_URISourceExpression_schemeOnly(self): srcExprFull = URISourceExpression("chrome-extension", "mkfokfffehpeedafpekjeddnmnjhmcmk", None, None) assert srcExprFull.schemeOnly() == URISourceExpression( "chrome-extension", None, None, None) srcExprIncomplete = URISourceExpression(None, "seclab.nu", None, None) assert srcExprIncomplete.schemeOnly() == SourceExpression.INVALID()
def test_URISourceExpression_eq(self): srcExprFull1 = URISourceExpression("http", "seclab.nu", 80, "/") srcExprFull2 = URISourceExpression("http", "seclab.nu", 80, "/") assert srcExprFull1 == srcExprFull2 assert hash(srcExprFull1) == hash(srcExprFull2) srcExprStar = URISourceExpression("http", "*.seclab.nu", None, None) assert srcExprFull1 != srcExprStar assert srcExprFull1 != SourceExpression.UNSAFE_EVAL()
class ReportDataReaderTest(unittest.TestCase): sampleURI1a = URI("http", "seclab.nu", None, None, None) sampleURI1b = URI("http", "seclab.nu", None, None, None) sampleURI2 = URI("http", "seclab.nu", None, "/blocked", "query") sampleDirective1a = Directive("default-src", ()) sampleDirective1b = Directive("default-src", ()) sampleDirective2a = Directive("script-src", (SourceExpression.UNSAFE_INLINE(), )) sampleDirective2b = Directive("script-src", (SourceExpression.UNSAFE_INLINE(), )) samplePolicy1a = Policy((sampleDirective1a, sampleDirective2a)) samplePolicy1b = Policy((sampleDirective1b, sampleDirective2b)) samplePolicy2 = Policy((sampleDirective1a, )) @pytest.fixture(autouse=True) def initdir(self, tmpdir): tmpdir.chdir() def setUp(self): self.fileIn = ReportDataReader(True) self.filename = "encodingdecoding.dat" self.fileOut = DataWriter(self.filename) def tearDown(self): pass def testReportCreation(self): """Writes a Report and loads it back as an object.""" report = Report({ "abc": True, "def": 1, "ghi": "http://seclab.nu/", "document-uri": ReportDataReaderTest.sampleURI1a, "violated-directive": ReportDataReaderTest.sampleDirective1a, "original-policy": ReportDataReaderTest.samplePolicy1a, "blocked-uri": ReportDataReaderTest.sampleURI2 }) self.fileOut.storeAll([report]) self.fileOut.close() dataOut = self.fileIn.loadAll(self.filename) assert len(dataOut) == 1 print report print dataOut[0] assert report in dataOut
def testPolicy_compareTo_recursive(self): pol1 = Policy([PolicyTest.sampleDirective6]) pol2 = Policy( [Directive("style-src", [SourceExpression.UNSAFE_INLINE()])]) assert pol1.compareTo(pol2) == ( set([pol2]), set([ Policy([Directive("style-src", [SelfSourceExpression.SELF()])]) ]), set([]))
def testPolicy_combinedPolicy_normal(self): pol1 = Policy([ PolicyTest.sampleDirective6, PolicyTest.sampleDirective2, PolicyTest.sampleDirective3 ]) pol2 = Policy( [PolicyTest.sampleDirective4, PolicyTest.sampleDirective7]) expected = Policy([ PolicyTest.sampleDirective6, PolicyTest.sampleDirective3, Directive("script-src", [ SourceExpression.UNSAFE_EVAL(), SourceExpression.UNSAFE_INLINE() ]) ]) assert pol1.combinedPolicy(pol1) == pol1 assert pol2.combinedPolicy(pol2) == pol2 assert pol1.combinedPolicy(pol2) == expected assert pol2.combinedPolicy(pol1) == expected
def testPolicy_combinedPolicy_validDefaultSrcOnly(self): """Combination of two policies with default directive is possible only if both policies contain only a default directive.""" pol1 = Policy([PolicyTest.sampleDirective1a]) pol2 = Policy([PolicyTest.sampleDirective9]) expected = Policy([ Directive("default-src", [ PolicyTest.sampleSourceExpression1, SourceExpression.UNSAFE_INLINE() ]) ]) assert pol1.combinedPolicy(pol2) == expected assert pol2.combinedPolicy(pol1) == expected
def test_InvalidSourceExpression_match(self): """The invalid source expression does not match anything.""" srcExpr = SourceExpression.INVALID() selfURI = SourceExpressionTest.uri_chromeExtension assert not srcExpr.matches(SourceExpressionTest.uri_empty, selfURI) assert not srcExpr.matches(SourceExpressionTest.uri_urlFull, selfURI) assert not srcExpr.matches(SourceExpressionTest.uri_urlSubstring, selfURI) assert not srcExpr.matches(SourceExpressionTest.uri_domain, selfURI) assert not srcExpr.matches(SourceExpressionTest.uri_data, selfURI) assert not srcExpr.matches(URI.INVALID(), selfURI) assert not srcExpr.matches(URI.EVAL(), selfURI) assert not srcExpr.matches(URI.INLINE(), selfURI)
class ReportTest(unittest.TestCase): sampleURI1a = URI("http", "seclab.nu", None, None, None) sampleURI1b = URI("http", "seclab.nu", None, None, None) sampleURI2 = URI("https", "seclab.ccs.neu.edu", None, None, "query") sampleDirective1a = Directive("default-src", (SelfSourceExpression.SELF(), )) sampleDirective1b = Directive("default-src", (SelfSourceExpression(), )) sampleDirective2a = Directive("script-src", (SourceExpression.UNSAFE_INLINE(), )) sampleDirective2b = Directive("script-src", (SourceExpression.UNSAFE_INLINE(), )) sampleDirective3 = Directive( "script-src", (URISourceExpression("http", "seclab.nu", None, None), )) samplePolicy1a = Policy((sampleDirective1a, sampleDirective2a)) samplePolicy1b = Policy((sampleDirective1b, sampleDirective2b)) def testReport_str_invalid(self): assert str(Report.INVALID()) == "[invalid]" def testReport_str_regular(self): """Extended object types should be serialised to strings when getting the report as a string.""" report = Report({ "violated-directive": ReportTest.sampleDirective2a, "original-policy": ReportTest.samplePolicy1a }) assert str(report) == """{"original-policy": "default-src 'self'; script-src 'unsafe-inline'",""" \ + """ "violated-directive": "script-src 'unsafe-inline'"}""" def testReport_str_primitives(self): """A Report with basic data types in it (instead of strings) should have them serialised to JSON-supported basic data types, not all strings.""" report = Report({"abc": True, "def": 1, "ghi": ReportTest.sampleURI1a}) expected = """{"abc": true, "def": 1, "ghi": "http://seclab.nu"}""" assert str(report) == expected def testReport_dict_iterateAndImmutable(self): report = Report({ "violated-directive": ReportTest.sampleDirective2a, "original-policy": ReportTest.samplePolicy1a }) assert len(report) == 2 assert "violated-directive" in report assert report["violated-directive"] == ReportTest.sampleDirective2a assert "original-policy" in report assert report["original-policy"] == ReportTest.samplePolicy1a for (key, value) in report.iteritems(): assert key in ("violated-directive", "original-policy") assert value in (ReportTest.sampleDirective2a, ReportTest.samplePolicy1a) with pytest.raises(TypeError): report["original-policy"] = None with pytest.raises(TypeError): report["something-else"] = 123 def testReport_eq(self): report1a = Report({ "violated-directive": ReportTest.sampleDirective2a, "original-policy": ReportTest.samplePolicy1a }) report1b = Report({ "violated-directive": ReportTest.sampleDirective2b, "original-policy": ReportTest.samplePolicy1b }) report2 = Report({ "violated-directive": ReportTest.sampleDirective1a, "original-policy": ReportTest.samplePolicy1a }) assert report1a == report1b assert hash(report1a) == hash(report1b) assert report1a != report2 assert report1a != Report.INVALID() assert report2 != Report.INVALID() def testReport_generatePolicy_regular(self): report = Report({ "blocked-uri": ReportTest.sampleURI1a, "violated-directive": ReportTest.sampleDirective2a, "document-uri": ReportTest.sampleURI2 }) assert report.generatePolicy("regular") == Policy( [ReportTest.sampleDirective3]) def testReport_generatePolicy_invalid(self): assert Report.INVALID().generatePolicy("regular") == 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 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 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 testReportParser_parse_typeFields(self): """Check that type indications for fields are properly parsed.""" report = """{"uri": "https://seclab.ccs.neu.edu?query", "directive": "script-src 'unsafe-inline'",""" \ + """ "policy": "script-src 'unsafe-inline'; default-src 'self'",""" \ + """ "nothing": "123"}""" cspReport = ReportParser(uriKeys=["uri", "url"], directiveKeys=["directive"], policyKeys=["policy"], requiredKeys=[], strict=True).parseString(report) expected = Report({ "uri": ReportTest.sampleURI2, "directive": ReportTest.sampleDirective2a, "policy": ReportTest.samplePolicy1a, "nothing": "123" }) assert cspReport == expected def testReportParser_parse_stringVsJSON(self): """Ensure the string parsing returns the same result as JSON parsing.""" reportJSON = {"something": 123, "uri": "http://seclab.nu"} reportString = """{"something": 123, "uri": "http://seclab.nu"}""" expected = Report({"something": 123, "uri": ReportTest.sampleURI1a}) parser = ReportParser(uriKeys=["uri"], requiredKeys=[], strict=True) parsedFromJSON = parser.parseJsonDict(reportJSON) parsedFromString = parser.parseString(reportString) print parsedFromJSON print parsedFromString assert parsedFromJSON == parsedFromString assert parsedFromJSON == expected def testReportParser_parse_fieldNameReplacements(self): """Checks that old field names are replaced correctly.""" report = """{"document-url": "http://seclab.nu", "original-policy": "default-src 'self'; script-src 'unsafe-inline'"}""" expected = Report({ "document-uri": ReportTest.sampleURI1a, "original-policy": ReportTest.samplePolicy1a }) parser = ReportParser( uriKeys=["document-uri"], policyKeys=["original-policy"], requiredKeys=["document-uri", "original-policy"], strict=True, keyNameReplacements={"document-url": "document-uri"}) cspReport = parser.parseString(report) assert cspReport == expected def testReportParser_parse_requiredFields(self): """Required fields must be present even if strict=False.""" report = """{"this-is": "a quite empty report"}""" expected = Report({"this-is": "a quite empty report"}) assert ReportParser(requiredKeys=[], strict=False).parseString(report) == expected assert ReportParser( requiredKeys=["does-not-exist"], strict=False).parseString(report) == Report.INVALID() def testReportParser_parse_emptyOrSelfURI(self): """This tests that the internal settings of the URI parser are chosen such that empty or self URIs are correctly handled.""" report = """{"empty-uri": "", "self-uri": "self", "document-uri": "http://seclab.nu"}""" expected = Report({ "empty-uri": URI.EMPTY(), "self-uri": ReportTest.sampleURI1a, "document-uri": ReportTest.sampleURI1a }) assert ReportParser(requiredKeys=[], strict=True, uriKeys=["empty-uri", "self-uri", "document-uri"]) \ .parseString(report) == expected def testReportParser_parse_failIfStrict(self): """The report must be declared invalid in strict mode when a child element is invalid.""" report = """{"invalid-policy": "awesomeness-src 'self'", "example": true}""" assert ReportParser(requiredKeys=[], strict=True, policyKeys=["invalid-policy"]) \ .parseString(report) == Report.INVALID() def testReportParser_parse_skipIfNotStrict(self): """Invalid portions of the report must be skipped in non-strict mode.""" report = """{"invalid-policy": "awesomeness-src 'self'", "example": true}""" expected = Report({"example": True}) assert ReportParser(requiredKeys=[], strict=False, policyKeys=["invalid-policy"]) \ .parseString(report) == expected def testReportParser_parse_inferSelfURI(self): """Tests if the self URI is correctly inferred from the "document-uri" field (even after renaming).""" report = """{"violated-directive": "default-src 'self'", "referrer": "",""" \ + """ "blocked-uri": "self", "document-URL":""" \ + """ "http://seclab.nu"}""" expected = Report({ "violated-directive": ReportTest.sampleDirective1a, "referrer": URI.EMPTY(), "blocked-uri": ReportTest.sampleURI1a, "document-uri": ReportTest.sampleURI1a }) parser = ReportParser( requiredKeys=["violated-directive", "document-uri", "blocked-uri"], strict=True, directiveKeys=["violated-directive"], uriKeys=["referrer", "blocked-uri", "document-uri"], keyNameReplacements={'document-url': 'document-uri'}) cspReport = parser.parseString(report) assert cspReport == expected def testReportParser_parse_selfURIFailStrict(self): """Tests that parsing fails if strict and no document-uri but another 'self' URI.""" report = """{"blocked-uri": "self", "other": "value"}""" parser = ReportParser(requiredKeys=[], strict=True, uriKeys=["blocked-uri", "document-uri"]) cspReport = parser.parseString(report) assert cspReport == Report.INVALID() def testReportParser_parse_selfURISkipStrict(self): """Tests that parsing fails if strict and no document-uri but another 'self' URI.""" report = """{"blocked-uri": "self", "other": "value"}""" expected = Report({"other": "value"}) parser = ReportParser(requiredKeys=[], strict=False, uriKeys=["blocked-uri", "document-uri"]) cspReport = parser.parseString(report) assert cspReport == expected def testReportParser_parse_unicode(self): """The JSON deserialiser returns strings as unicode objects. Check that they are correctly parsed in URIs.""" fullReport = """{"remote-addr": "XXX", "policy-type": "regular", "http-user-agent":""" \ + """ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:27.0) Gecko/20100101 Firefox/27.0",""" \ + """ "timestamp-utc": "2014-03-01 12:13:14.156789", "csp-report": {"violated-directive":""" \ + """ "img-src 'none'", "referrer": "http://handbook5.com/a/a-security-analysis-of-amazon%E2%80%99s-elastic-compute-cloud-service-w14847.html",""" \ + """ "blocked-uri": "http://www.iseclab.org/images/anr.png", "document-uri":""" \ + """ "http://www.iseclab.org/?p"}, "header-type": "standard"}""" expected = Report({ "violated-directive": Directive("img-src", ()), "referrer": URI( "http", "handbook5.com", None, u"/a/a-security-analysis-of-amazon’s-elastic-compute-cloud-service-w14847.html" ), "blocked-uri": URI("http", "www.iseclab.org", None, u"/images/anr.png"), "document-uri": URI("http", "www.iseclab.org", None, u"/", "p") }) parser = ReportParser(requiredKeys=[]) jsonReport = json.loads(fullReport) cspReport = parser.parseJsonDict(jsonReport["csp-report"]) assert cspReport == expected
def test_EvalSourceExpression_str(self): srcExprEval = SourceExpression.UNSAFE_EVAL() assert str(srcExprEval) == "'unsafe-eval'"
def test_InlineSourceExpression_str(self): srcExprInline = SourceExpression.UNSAFE_INLINE() assert str(srcExprInline) == "'unsafe-inline'"
def test_SelfSourceExpression_eq(self): srcExpr1 = SelfSourceExpression() srcExpr2 = SelfSourceExpression.SELF() assert srcExpr1 == srcExpr2 assert hash(srcExpr1) == hash(srcExpr2) assert srcExpr1 != SourceExpression.UNSAFE_EVAL()
def testDirective_init_removeInvalidSourceExpressions(self): assert Directive("img-src", [SourceExpression.INVALID()]) == Directive( "img-src", [])
def test_parse_unsupported_scheme_fails(self): exprStr = "my-scheme://domain/path" srcExpr = SourceExpressionParser(knownSchemes=('http', 'https')).parse(exprStr) assert srcExpr == SourceExpression.INVALID()
def testDirective_generateDirective_eval_special(self): violated = Directive.EVAL_SCRIPT_BASE_RESTRICTION() generated = violated.generateDirective("eval", DirectiveTest.sampleURI2) assert generated == Directive("script-src", [SourceExpression.UNSAFE_EVAL()])
def testDirective_generateDirective_eval(self): violated = Directive("script-src", [DirectiveTest.sampleSrcExpr1a]) generated = violated.generateDirective("eval", URI.EMPTY()) assert generated == Directive("script-src", [SourceExpression.UNSAFE_EVAL()])
def testDirective_generateDirective_inline(self): violated = Directive("style-src", [DirectiveTest.sampleSrcExpr2]) generated = violated.generateDirective("inline", URI.EMPTY()) assert generated == Directive("style-src", [SourceExpression.UNSAFE_INLINE()])
def testLogEntry_generatePolicy_standard(self): assert LogEntryTest.cspLogEntry.generatePolicy() == Policy( [Directive("style-src", [SourceExpression.UNSAFE_INLINE()])])
class LogEntryTest(unittest.TestCase): starSourceExpr = URISourceExpression(None, "*", None, None) strLogEntry = """{"csp-report": {"blocked-uri": "", "document-uri": "http://seclab.nu/csp-test.html", """ \ + """"original-policy": "default-src *; script-src 'unsafe-eval' *; style-src *", """ \ + """"referrer": "", "status-code": 200, "violated-directive": "style-src *"}, """ \ + """"header-type": "webkit", "http-user-agent": """ \ + """"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, """ \ + """like Gecko) Chrome/31.0.1650.63 Safari/537.36", "policy-type": "inline", """ \ + """"remote-addr": "1.2.3.4", "timestamp-utc": "2013-12-14 01:02:03.456789"}""" logEntryData = {u"csp-report": Report({u"document-uri": URI("http", "seclab.nu", None, u"/csp-test.html"), u"referrer": URI.EMPTY(), u"violated-directive": Directive("style-src", (starSourceExpr,)), u"original-policy": Policy((Directive("default-src", (starSourceExpr,)), Directive("script-src", (starSourceExpr, SourceExpression.UNSAFE_EVAL())), Directive("style-src", (starSourceExpr,)))), u"blocked-uri": URI.EMPTY(), u"status-code": 200 }), u"remote-addr": u"1.2.3.4", u"http-user-agent": u"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) " \ + u"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36", u"timestamp-utc": u"2013-12-14 01:02:03.456789", u"policy-type": u"inline", u"header-type": u"webkit" } cspLogEntry = LogEntry(logEntryData) def testLogEntry_str_invalid(self): assert str(LogEntry.INVALID()) == "[invalid]" def testLogEntry_str_regular(self): assert str(LogEntryTest.cspLogEntry) == LogEntryTest.strLogEntry def testLogEntry_dict_iterateAndImmutable(self): assert len(LogEntryTest.cspLogEntry) == 6 assert "http-user-agent" in LogEntryTest.cspLogEntry assert LogEntryTest.cspLogEntry["remote-addr"] == "1.2.3.4" for key in LogEntryTest.cspLogEntry.keys(): assert key in ("csp-report", "remote-addr", "http-user-agent", "timestamp-utc", "policy-type", "header-type") with pytest.raises(TypeError): LogEntryTest.cspLogEntry["csp-report"] = None with pytest.raises(TypeError): LogEntryTest.cspLogEntry["something-else"] = 123 def testLogEntry_eq(self): assert LogEntryTest.cspLogEntry != LogEntry.INVALID() def testLogEntry_generatePolicy_standard(self): assert LogEntryTest.cspLogEntry.generatePolicy() == Policy( [Directive("style-src", [SourceExpression.UNSAFE_INLINE()])]) def testLogEntry_generatePolicy_invalid(self): assert LogEntry.INVALID().generatePolicy() == 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 testLogEntryParser_parse(self): parser = LogEntryParser(strict=True) parsed = parser.parseString(LogEntryTest.strLogEntry) print parsed._entryData print LogEntryTest.cspLogEntry._entryData print parsed._entryData[ 'csp-report'] == LogEntryTest.cspLogEntry._entryData['csp-report'] assert parsed == LogEntryTest.cspLogEntry
class PolicyTest(unittest.TestCase): sampleURI1a = URI("http", "seclab.nu", None, None, None) sampleURI1b = URI("http", "seclab.nu", None, None, None) sampleURI2 = URI("http", "seclab.ccs.neu.edu", None, None, None) sampleSourceExpression1 = URISourceExpression("http", "seclab.nu", None, None) sampleSourceExpression2 = SelfSourceExpression.SELF() sampleDirective1a = Directive( "default-src", (URISourceExpression("http", "seclab.nu", None, None), )) sampleDirective1b = Directive( "default-src", (URISourceExpression("http", "seclab.nu", None, None), )) sampleDirective2 = Directive("script-src", (SourceExpression.UNSAFE_INLINE(), )) sampleDirective3 = Directive( "img-src", (URISourceExpression(None, "*", None, None), )) sampleDirective4 = Directive("img-src", ()) sampleDirective5 = Directive( "connect-src", (SelfSourceExpression.SELF(), URISourceExpression("chrome-extension", None, None, None), URISourceExpression("https", "abc.seclab.nu", None, "/path"))) sampleDirective6 = Directive( "style-src", (SourceExpression.UNSAFE_INLINE(), SelfSourceExpression.SELF())) sampleDirective7 = Directive("script-src", (SourceExpression.UNSAFE_EVAL(), )) sampleDirective8 = Directive("style-src", (SelfSourceExpression.SELF(), )) sampleDirective9 = Directive("default-src", (SourceExpression.UNSAFE_INLINE(), )) def testPolicy_str_invalid(self): assert str(Policy.INVALID()) == "[invalid]" def testPolicy_str_empty(self): assert str(Policy(())) == "" def testPolicy_str_normal(self): pol = Policy( (PolicyTest.sampleDirective1a, PolicyTest.sampleDirective2, PolicyTest.sampleDirective3)) assert str( pol ) == "default-src http://seclab.nu; img-src *; script-src 'unsafe-inline'" 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_init_duplicateType(self): pol = Policy( (PolicyTest.sampleDirective1a, PolicyTest.sampleDirective3, PolicyTest.sampleDirective4)) directives = pol.getDirectives() assert PolicyTest.sampleDirective1a in directives and (PolicyTest.sampleDirective3 in directives \ or PolicyTest.sampleDirective4 in directives) def testPolicy_init_duplicateDirective(self): pol = Policy( (PolicyTest.sampleDirective1a, PolicyTest.sampleDirective1b, PolicyTest.sampleDirective2)) assert pol == Policy( (PolicyTest.sampleDirective1a, PolicyTest.sampleDirective2)) assert pol == Policy( (PolicyTest.sampleDirective1b, PolicyTest.sampleDirective2)) def testPolicy_init_noDuplicatesHere(self): directives = set([ PolicyTest.sampleDirective1a, PolicyTest.sampleDirective2, PolicyTest.sampleDirective5 ]) pol = Policy(directives) assert pol.getDirectives() == directives def testPolicy_init_removeNotRegularDirective(self): pol = Policy([ PolicyTest.sampleDirective1a, Directive.INVALID(), Directive.EVAL_SCRIPT_BASE_RESTRICTION() ]) expected = Policy([PolicyTest.sampleDirective1a]) assert pol == expected 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_matches_matchingDirectiveType(self): """Policy contains directive of resource type that matches.""" pol = Policy( (PolicyTest.sampleDirective1a, PolicyTest.sampleDirective5)) selfURI = PolicyTest.sampleURI2 assert pol.matches( URI("https", "abc.seclab.nu", 443, "/path", "some-query"), "connect-src", selfURI) def testPolicy_matches_nonMatchingDirectiveTypeButDefaultMatches(self): """Policy contains directive of resource type that does not match and default directive that does match, but it should not be applied.""" pol = Policy( (PolicyTest.sampleDirective1a, PolicyTest.sampleDirective5)) selfURI = PolicyTest.sampleURI2 assert not pol.matches(PolicyTest.sampleURI1a, "connect-src", selfURI) def testPolicy_matches_defaultSrcMatches(self): """Policy contains no directive of resource type, but a default directive that matches.""" pol = Policy( (PolicyTest.sampleDirective1a, PolicyTest.sampleDirective5)) selfURI = PolicyTest.sampleURI2 assert pol.matches(PolicyTest.sampleURI1a, "script-src", selfURI) def testPolicy_matches_defaultSrcNoMatch(self): """Policy contains no directive of resource type, but a default directive. Default-src does not match.""" pol = Policy((PolicyTest.sampleDirective1a, )) selfURI = PolicyTest.sampleURI1a assert not pol.matches(PolicyTest.sampleURI2, "img-src", selfURI) def testPolicy_matches_defaultSrcNotUsable(self): """Policy contains no directive of resource type, but a default directive. Default-src cannot be used in this case because not allowed for resource type.""" pol = Policy((PolicyTest.sampleDirective1a, )) selfURI = PolicyTest.sampleURI2 assert not pol.matches(PolicyTest.sampleURI1a, "form-action", selfURI) def testPolicy_matches_defaultSrcNotSpecified_match(self): """Policy contains no directive of resource type, and no default directive either. Should assume 'default-src *' (match for regular resources).""" pol = Policy((PolicyTest.sampleDirective5, )) selfURI = PolicyTest.sampleURI1a assert pol.matches(PolicyTest.sampleURI2, "script-src", selfURI) def testPolicy_matches_defaultSrcNotSpecified_noMatch(self): """Policy contains no directive of resource type, and no default directive either. Should assume 'default-src *' (no match for inline/eval resources).""" pol = Policy((PolicyTest.sampleDirective5, )) selfURI = PolicyTest.sampleURI1a assert not pol.matches(URI.INLINE(), "script-src", selfURI) assert not pol.matches(URI.EVAL(), "script-src", selfURI) def testPolicyParser_parse_normal(self): simplePolicy = """connect-src 'self' https://abc.seclab.nu/path chrome-extension:; img-src 'none'""" cspSimplePolicy = PolicyParser().parse(simplePolicy) print cspSimplePolicy assert cspSimplePolicy == Policy( [PolicyTest.sampleDirective4, PolicyTest.sampleDirective5]) 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() def testPolicyParser_parse_nonstrict_onlyValidDirectives(self): """Ensures that a CSP policy does ignore invalid portions in non-strict mode if it contains an invalid directive.""" policy = """img-src 'none'; script-src""" cspPolicy = PolicyParser(strict=False).parse(policy) assert cspPolicy == Policy([PolicyTest.sampleDirective4]) def testPolicyParser_parse_ignoredDirective(self): """Ensure that unsupported directives ('report-uri' etc.) are skipped without causing an error.""" policy = """img-src *; report-uri /csp.cgi""" cspPolicy = PolicyParser(strict=True, ignoredTypes=("report-uri", )).parse(policy) assert cspPolicy == Policy([PolicyTest.sampleDirective3]) def testPolicyParser_parse_defaultSrcRewriting(self): """The default directive is used for each type that is not specifically defined (if the flag is enabled).""" policy = """default-src 'self' http://seclab.nu; connect-src 'self' https://abc.seclab.nu/path chrome-extension:""" cspPolicy = PolicyParser(expandDefaultSrc=True, defaultSrcTypes=("img-src", "connect-src")).parse(policy) assert cspPolicy == Policy([ PolicyTest.sampleDirective5, Directive("img-src", [ PolicyTest.sampleSourceExpression1, PolicyTest.sampleSourceExpression2 ]) ]) def testPolicyParser_parse_noDefaultSrcRewriting(self): policy = """default-src 'self' http://seclab.nu""" cspPolicy = PolicyParser(expandDefaultSrc=False, defaultSrcTypes=("img-src", "connect-src")).parse(policy) assert cspPolicy == Policy([ Directive("default-src", [ PolicyTest.sampleSourceExpression1, PolicyTest.sampleSourceExpression2 ]) ]) def testPolicyParser_parse_duplicates(self): """The CSP standard mandates that only the first directive of each type should be used.""" duplicatePolicy = """connect-src 'self' chrome-extension: https://abc.seclab.nu/path; """ \ + """font-src 'self' http://seclab.nu; """ \ + """connect-src 'self' https://example.com""" cspPolicy = PolicyParser().parse(duplicatePolicy) assert cspPolicy == Policy([ PolicyTest.sampleDirective5, Directive("font-src", [ PolicyTest.sampleSourceExpression1, PolicyTest.sampleSourceExpression2 ]) ]) def testPolicy_combinedPolicy_normal(self): pol1 = Policy([ PolicyTest.sampleDirective6, PolicyTest.sampleDirective2, PolicyTest.sampleDirective3 ]) pol2 = Policy( [PolicyTest.sampleDirective4, PolicyTest.sampleDirective7]) expected = Policy([ PolicyTest.sampleDirective6, PolicyTest.sampleDirective3, Directive("script-src", [ SourceExpression.UNSAFE_EVAL(), SourceExpression.UNSAFE_INLINE() ]) ]) assert pol1.combinedPolicy(pol1) == pol1 assert pol2.combinedPolicy(pol2) == pol2 assert pol1.combinedPolicy(pol2) == expected assert pol2.combinedPolicy(pol1) == expected 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 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 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_validDefaultSrcOnly(self): """Combination of two policies with default directive is possible only if both policies contain only a default directive.""" pol1 = Policy([PolicyTest.sampleDirective1a]) pol2 = Policy([PolicyTest.sampleDirective9]) expected = Policy([ Directive("default-src", [ PolicyTest.sampleSourceExpression1, SourceExpression.UNSAFE_INLINE() ]) ]) assert pol1.combinedPolicy(pol2) == expected assert pol2.combinedPolicy(pol1) == expected 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 testPolicy_withoutPaths_schemeOnly(self): withPaths = Policy( [PolicyTest.sampleDirective3, PolicyTest.sampleDirective5]) withoutPaths = Policy([ PolicyTest.sampleDirective3, PolicyTest.sampleDirective5.withoutPaths(["http"]) ]) assert withPaths.withoutPaths(["http"]) == withoutPaths def testPolicy_asBasicPolicies_single(self): assert Policy.INVALID().asBasicPolicies() == set([]) assert Policy([PolicyTest.sampleDirective1a]).asBasicPolicies() == set( [Policy([PolicyTest.sampleDirective1a])]) def testPolicy_asBasicPolicies_multiple(self): assert Policy( [PolicyTest.sampleDirective1a, PolicyTest.sampleDirective2]).asBasicPolicies() == set([ Policy([PolicyTest.sampleDirective1a]), Policy([PolicyTest.sampleDirective2]) ]) def testPolicy_asBasicPolicies_recursive(self): expected = set( map(lambda direct: Policy((direct, )), PolicyTest.sampleDirective5.asBasicDirectives())) actual = Policy([PolicyTest.sampleDirective5]).asBasicPolicies() assert actual == expected 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 testPolicy_isBasicNonePolicy(self): assert Policy.INVALID().isBasicNonePolicy() == False assert Policy([PolicyTest.sampleDirective6 ]).isBasicNonePolicy() == False assert Policy([PolicyTest.sampleDirective1a ]).isBasicNonePolicy() == False assert Policy( [PolicyTest.sampleDirective2, PolicyTest.sampleDirective4]).isBasicNonePolicy() == False assert Policy([PolicyTest.sampleDirective4 ]).isBasicNonePolicy() == True 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 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_compareTo_regular(self): pol1 = Policy( [PolicyTest.sampleDirective7, PolicyTest.sampleDirective8]) pol2 = Policy( [PolicyTest.sampleDirective7, PolicyTest.sampleDirective9]) assert pol1.compareTo(pol2) == (set([ Policy([PolicyTest.sampleDirective7]) ]), set([Policy([PolicyTest.sampleDirective8]) ]), set([Policy([PolicyTest.sampleDirective9])])) assert pol2.compareTo(pol1) == (set([ Policy([PolicyTest.sampleDirective7]) ]), set([Policy([PolicyTest.sampleDirective9]) ]), set([Policy([PolicyTest.sampleDirective8])])) assert pol1.compareTo(pol1) == (set([ Policy([PolicyTest.sampleDirective7]), Policy([PolicyTest.sampleDirective8]) ]), set([]), set([])) def testPolicy_compareTo_recursive(self): pol1 = Policy([PolicyTest.sampleDirective6]) pol2 = Policy( [Directive("style-src", [SourceExpression.UNSAFE_INLINE()])]) assert pol1.compareTo(pol2) == ( set([pol2]), set([ Policy([Directive("style-src", [SelfSourceExpression.SELF()])]) ]), set([]))
def testDirective_str_regular(self): srcExpr1 = URISourceExpression("http", "seclab.nu", "*", None) srcExpr2 = SourceExpression.UNSAFE_INLINE() srcExpr3 = SelfSourceExpression.SELF() assert str(Directive("style-src", [srcExpr1, srcExpr2, srcExpr3])) \ == "style-src 'self' 'unsafe-inline' http://seclab.nu:*"
def test_parse_eval(self): srcExpr = SourceExpressionParser().parse("'unsafe-eval'") assert srcExpr == SourceExpression.UNSAFE_EVAL() assert srcExpr.getType() == "unsafe-eval" assert srcExpr == SourceExpressionParser().parse("'UNSAFE-EVAL'")
def testDirective_generateDirective_inline_special_script(self): violated = Directive.INLINE_SCRIPT_BASE_RESTRICTION() generated = violated.generateDirective("inline", DirectiveTest.sampleURI1) assert generated == Directive("script-src", [SourceExpression.UNSAFE_INLINE()])
def test_parse_inline(self): srcExpr = SourceExpressionParser().parse("'unsafe-inline'") assert srcExpr == SourceExpression.UNSAFE_INLINE() assert srcExpr.getType() == "unsafe-inline" assert srcExpr == SourceExpressionParser().parse("'UNSAFE-INLINE'")