Esempio n. 1
0
 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()
Esempio n. 2
0
 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
Esempio n. 3
0
 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
Esempio n. 4
0
 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()
Esempio n. 5
0
 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()
Esempio n. 6
0
 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
Esempio n. 7
0
 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
Esempio n. 8
0
 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
Esempio n. 9
0
 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
Esempio n. 10
0
 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
Esempio n. 11
0
 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
Esempio n. 12
0
 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
Esempio n. 13
0
 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
Esempio n. 14
0
 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
Esempio n. 15
0
 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
Esempio n. 16
0
class ReportDataReader(DataReader):
    '''
    Loads CSP violation reports from files. The file format is one JSON-encoded report per line.
    '''

    def __init__(self, printErrorMessages=False):
        DataReader.__init__(self, printErrorMessages)
        self._parser = ReportParser()
        
    def load(self, filename, callbackFunction):
        """
        Opens 'filename' and passes each valid Report to 'callbackFunction'. Returns nothing.
        """
        def convert(line):
            report = self._parser.parseString(line)
            if report is not Report.INVALID():
                callbackFunction(report)
            elif self._printErrorMessages:
                print "Could not parse report '%s'" % line
        DataReader.load(self, filename, convert)
Esempio n. 17
0
 def __init__(
     self,
     uriKeys=('blocked-uri', 'document-uri', 'referrer'),
     directiveKeys=('violated-directive', ),
     policyKeys=("original-policy", ),
     keyNameReplacements={'document-url': 'document-uri'},
     requiredKeys=('blocked-uri', 'violated-directive', 'document-uri'),
     strict=True,
     addSchemeToURIs=False,
     defaultURIScheme="http",
     addPortToURIs=False,
     defaultURIPort=80,
     schemePortMappings={
         'http': 80,
         'https': 443,
         'data': None,
         'chrome-extension': None,
         'safari-extension': None,
         'chromenull': None,
         'chromeinvoke': None,
         'chromeinvokeimmediate': None,
         'mx': None,
         'moz-icon': None,
         'about': None,
         'view-source': None
     },
     portSchemeMappings={
         80: 'http',
         443: 'https',
         8080: 'http'
     },
     directiveTypeTranslations={"xhr-src": "connect-src"},
     allowedDirectiveTypes=("base-uri", "child-src", "connect-src",
                            "default-src", "font-src", "form-action",
                            "frame-ancestors", "frame-src", "img-src",
                            "media-src", "object-src", "script-src",
                            "style-src"),
     ignoredDirectiveTypes=("plugin-types", "referrer", "reflected-xss",
                            "report-uri", "sandbox"),
     expandDefaultSrc=False,
     defaultSrcTypes=("child-src", "connect-src", "font-src", "img-src",
                      "media-src", "object-src", "script-src",
                      "style-src")):
     """
     Creates a new LogEntryParser object configured with the following parameters:
     
     'uriKeys': an iterable of key (entry) names of which the corresponding values, if present,
                         will be parsed and replaced with an URI object.
     'directiveKeys': an iterable of key (entry) names of which the corresponding values, if present,
                         will be parsed and replaced with a Directive object.
     'policyKeys': an iterable of key (entry) names of which the corresponding values, if present,
                         will be parsed and replaced with a Policy object.
     The 'uriKeys', 'directiveKeys', and 'policyKeys' lists are mutually exclusive (a key may appear
                         in at most one of these lists.)
     'keyNameReplacements': a dictionary of old key (entry) names mapped to the new name to be given
                         to them before any further parsing. This can be used to adjust to renamed 
                         fields in the violation reports generated by different browser versions.
     'requiredKeys': an iterable of key (entry) names that are mandatory and must appear in the report
                         with a valid value (if parsed, cannot be URI.INVALID()/Directive.INVALID()/
                         Policy.INVALID()). If this constraint is violated, the parsing result will be
                         Report.INVALID() (independent of the 'strict' setting). This restriction is 
                         applied after performing key name replacement.
     'strict': whether a parsing error of a child element should be ignored if it can be fixed (if
                         set to False, invalid children will be skipped), or if any parsing error
                         should cause the Report to become Report.INVALID() (if set to True).
     'addSchemeToURIs': [for parsed URIs] whether to add the scheme. (See URIParser for details.)
     'defaultURIScheme': [for parsed URIs] if the scheme should be added, the default scheme to be 
                         assumed if nothing can be inferred from the port. (See URIParser for details.)
     'addPortToURIs': [for parsed URIs] whether to add the port. (See URIParser for details.)
     'defaultURIPort': [for parsed URIs] if the port should be added, the default port to be assumed
                         if nothing can be inferred from the scheme. (See URIParser for details.)
     'schemePortMappings': [for parsed URIs and policy/directive parsing] A map from scheme names to the 
                         corresponding default port, or None if the scheme does not use ports. Any scheme
                         that may appear inside an URI, source expression, directive or policy should be
                         listed. (See URIParser and SourceExpressionParser for details.)
     'portSchemeMappings': [for parsed URIs] A map from port numbers to scheme names (only for "real" ports).
                         See URIParser for details.
     'directiveTypeTranslations': [for parsed directives and policies] A map from the old directive name to
                         the new name to be used. (See DirectiveParser for details.)
     'allowedDirectiveTypes': [for parsed directives and policies] a list of directive types that are allowed.
                         (See DirectiveParser or PolicyParser for details.)
     'ignoredDirectiveTypes': [for parsed policies] a list of directive types that are ignored when parsing
                         policies. (See PolicyParser for details.)
     'expandDefaultSrc': [for parsed policies] if set to True, each "default-src" directive in a parsed policy
                         will be expanded to the corresponding elementary directive types, if not yet present.
                         (See PolicyParser for details.)
     'defaultSrcTypes': [for parsed policies] when "default-src" is expanded, the elementary directive types
                         that will be added to replace the default policy. (See PolicyParser for details.)
     """
     self._strict = strict
     self._reportParser = ReportParser(
         uriKeys, directiveKeys, policyKeys, keyNameReplacements,
         requiredKeys, strict, addSchemeToURIs, defaultURIScheme,
         addPortToURIs, defaultURIPort, schemePortMappings,
         portSchemeMappings, directiveTypeTranslations,
         allowedDirectiveTypes, ignoredDirectiveTypes, expandDefaultSrc,
         defaultSrcTypes)
Esempio n. 18
0
 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()
Esempio n. 19
0
 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
Esempio n. 20
0
 def __init__(self, printErrorMessages=False):
     DataReader.__init__(self, printErrorMessages)
     self._parser = ReportParser()
Esempio n. 21
0
 def __init__(self, 
              uriKeys=('blocked-uri', 'document-uri', 'referrer'),
              directiveKeys=('violated-directive',),
              policyKeys=("original-policy",),
              keyNameReplacements={'document-url': 'document-uri'},
              requiredKeys=('blocked-uri', 'violated-directive', 'document-uri'),
              strict=True,
              addSchemeToURIs=False,
              defaultURIScheme="http",
              addPortToURIs=False,
              defaultURIPort=80,
              schemePortMappings={'http': 80, 'https': 443, 'data': None, 'chrome-extension': None, 
                                  'safari-extension': None, 'chromenull': None, 'chromeinvoke': None,
                                  'chromeinvokeimmediate': None, 'mx': None, 'moz-icon': None,
                                  'about': None, 'view-source': None},
              portSchemeMappings={80: 'http', 443: 'https', 8080: 'http'},
              directiveTypeTranslations={"xhr-src": "connect-src"}, 
              allowedDirectiveTypes=("base-uri", "child-src", "connect-src", "default-src",
                            "font-src", "form-action", "frame-ancestors", "frame-src",
                            "img-src", "media-src", "object-src", "script-src", "style-src"),
              ignoredDirectiveTypes=("plugin-types", "referrer", "reflected-xss", "report-uri", "sandbox"),
              expandDefaultSrc=False,
              defaultSrcTypes=("child-src", "connect-src", "font-src", "img-src", "media-src",
                               "object-src", "script-src", "style-src")):
     """
     Creates a new LogEntryParser object configured with the following parameters:
     
     'uriKeys': an iterable of key (entry) names of which the corresponding values, if present,
                         will be parsed and replaced with an URI object.
     'directiveKeys': an iterable of key (entry) names of which the corresponding values, if present,
                         will be parsed and replaced with a Directive object.
     'policyKeys': an iterable of key (entry) names of which the corresponding values, if present,
                         will be parsed and replaced with a Policy object.
     The 'uriKeys', 'directiveKeys', and 'policyKeys' lists are mutually exclusive (a key may appear
                         in at most one of these lists.)
     'keyNameReplacements': a dictionary of old key (entry) names mapped to the new name to be given
                         to them before any further parsing. This can be used to adjust to renamed 
                         fields in the violation reports generated by different browser versions.
     'requiredKeys': an iterable of key (entry) names that are mandatory and must appear in the report
                         with a valid value (if parsed, cannot be URI.INVALID()/Directive.INVALID()/
                         Policy.INVALID()). If this constraint is violated, the parsing result will be
                         Report.INVALID() (independent of the 'strict' setting). This restriction is 
                         applied after performing key name replacement.
     'strict': whether a parsing error of a child element should be ignored if it can be fixed (if
                         set to False, invalid children will be skipped), or if any parsing error
                         should cause the Report to become Report.INVALID() (if set to True).
     'addSchemeToURIs': [for parsed URIs] whether to add the scheme. (See URIParser for details.)
     'defaultURIScheme': [for parsed URIs] if the scheme should be added, the default scheme to be 
                         assumed if nothing can be inferred from the port. (See URIParser for details.)
     'addPortToURIs': [for parsed URIs] whether to add the port. (See URIParser for details.)
     'defaultURIPort': [for parsed URIs] if the port should be added, the default port to be assumed
                         if nothing can be inferred from the scheme. (See URIParser for details.)
     'schemePortMappings': [for parsed URIs and policy/directive parsing] A map from scheme names to the 
                         corresponding default port, or None if the scheme does not use ports. Any scheme
                         that may appear inside an URI, source expression, directive or policy should be
                         listed. (See URIParser and SourceExpressionParser for details.)
     'portSchemeMappings': [for parsed URIs] A map from port numbers to scheme names (only for "real" ports).
                         See URIParser for details.
     'directiveTypeTranslations': [for parsed directives and policies] A map from the old directive name to
                         the new name to be used. (See DirectiveParser for details.)
     'allowedDirectiveTypes': [for parsed directives and policies] a list of directive types that are allowed.
                         (See DirectiveParser or PolicyParser for details.)
     'ignoredDirectiveTypes': [for parsed policies] a list of directive types that are ignored when parsing
                         policies. (See PolicyParser for details.)
     'expandDefaultSrc': [for parsed policies] if set to True, each "default-src" directive in a parsed policy
                         will be expanded to the corresponding elementary directive types, if not yet present.
                         (See PolicyParser for details.)
     'defaultSrcTypes': [for parsed policies] when "default-src" is expanded, the elementary directive types
                         that will be added to replace the default policy. (See PolicyParser for details.)
     """
     self._strict = strict
     self._reportParser = ReportParser(uriKeys, directiveKeys, policyKeys, 
                                       keyNameReplacements, requiredKeys, strict, addSchemeToURIs, 
                                       defaultURIScheme, addPortToURIs, defaultURIPort, schemePortMappings, 
                                       portSchemeMappings, directiveTypeTranslations, allowedDirectiveTypes, 
                                       ignoredDirectiveTypes, expandDefaultSrc, defaultSrcTypes)