def generatePolicy(self, reportType): """ Generates a new basic policy that allows exactly the kind of event that caused this CSP violation report, assuming the given 'reportType' (permitted values are 'regular', 'eval', and 'inline'). This assumes that this report contains a specific violated-directive field (it may not be 'default-src'). If any inconsistent reports are used to generate policies, the policies themselves will be inconsistent. 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 "type" parameter in the report-uri is equivalent to the 'reportType' parameter of this method. The results should also be filtered to ensure that only reports sent by fully compatible browsers are taken into account. This implementation does not handle URIs in any special way. That is, it does not add or remove ports, path/query components, or replace them with the 'self' keyword. 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.) The result is Policy.INVALID() if (1) the violated directive is missing, Directive.INVALID() or 'default-src', or a special type incompatible with 'reportType', (2) if 'reportType' is none out of 'regular', 'inline' or 'eval', (3) the 'blocked-uri' is URI.INVALID() or not a regular URI in the 'reportType'=='regular' case. """ if (self == Report.INVALID() or 'violated-directive' not in self or 'blocked-uri' not in self): return Policy.INVALID() violated = self['violated-directive'] blocked = self['blocked-uri'] generated = violated.generateDirective(reportType, blocked) if generated == Directive.INVALID(): return Policy.INVALID() else: return Policy((generated,))
def parseJsonDict(self, jsonReport): """ Parses the given 'jsonReport' according to the parameters set in the constructor of this ReportParser and returns a Report object. 'jsonReport' is expected to be a Python dict object with attribute names and values corresponding to the definition of CSP violation reports. If 'jsonReport' cannot be parsed because it is syntactically invalid (or empty), Report.INVALID() will be returned. Depending on the configuration of this ReportParser object, some attributes will be parsed to replace their plain string values with a more high-level object representation. """ # replace names renamedReport = dict(map(lambda (key, val): (self._replaceName(key), val), jsonReport.iteritems())) # convert data in report convertedReport = {} deferredSelfURIs = set([]) # all key names that have URIs that are exactly 'self' (handle after parsing everything else) for (key, value) in renamedReport.iteritems(): if key in self._uriKeys: if value.lower().strip() == "self": deferredSelfURIs.add(key) continue else: value = self._uriParser.parse(value) elif key in self._directiveKeys: value = self._directiveParser.parse(value) elif key in self._policyKeys: value = self._policyParser.parse(value) if value in (URI.INVALID(), Directive.INVALID(), Policy.INVALID()): if self._strict: return Report.INVALID() else: continue convertedReport[key] = value # handle deferred parsing of 'self' URIs (they represent the document-uri) for key in deferredSelfURIs: if "document-uri" in self._uriKeys and "document-uri" in convertedReport: convertedReport[key] = convertedReport["document-uri"] elif self._strict: return Report.INVALID() for requiredKey in self._requiredKeys: if not requiredKey in convertedReport: return Report.INVALID() return Report(convertedReport)