From b90bac7d509520071f917e0f4c6b706b31608e4a Mon Sep 17 00:00:00 2001 From: Daniel Veditz Date: Tue, 10 Jul 2012 00:44:05 -0700 Subject: [PATCH] bug 767778 bring report struct in-line w/1.0 spec; include original URI for redirects r=sstamm, a=akeybl --- content/base/src/contentSecurityPolicy.js | 74 ++++++++++++++--------- content/base/src/nsCSPService.cpp | 7 ++- content/base/test/test_bug548193.html | 4 +- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/content/base/src/contentSecurityPolicy.js b/content/base/src/contentSecurityPolicy.js index 12dc969e9732..08131e7badca 100644 --- a/content/base/src/contentSecurityPolicy.js +++ b/content/base/src/contentSecurityPolicy.js @@ -37,6 +37,7 @@ function ContentSecurityPolicy() { this._policy._allowEval = true; this._request = ""; + this._referrer = ""; this._docRequest = null; CSPdebug("CSP POLICY INITED TO 'default-src *'"); } @@ -152,13 +153,13 @@ ContentSecurityPolicy.prototype = { switch (aViolationType) { case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_SCRIPT: if (!this._policy.allowsInlineScripts) - this._asyncReportViolation('self','inline script base restriction', + this._asyncReportViolation('self',null,'inline script base restriction', 'violated base restriction: Inline Scripts will not execute', aSourceFile, aScriptSample, aLineNum); break; case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_EVAL: if (!this._policy.allowsEvalInScripts) - this._asyncReportViolation('self','eval script base restriction', + this._asyncReportViolation('self',null,'eval script base restriction', 'violated base restriction: Code will not be created from strings', aSourceFile, aScriptSample, aLineNum); break; @@ -188,25 +189,18 @@ ContentSecurityPolicy.prototype = { function(aChannel) { if (!aChannel) return; - // grab the request line - var internalChannel = null; - try { - internalChannel = aChannel.QueryInterface(Ci.nsIHttpChannelInternal); - } catch (e) { - CSPdebug("No nsIHttpChannelInternal for " + aChannel.URI.asciiSpec); - } - this._request = aChannel.requestMethod + " " + aChannel.URI.asciiSpec; + // Save the docRequest for fetching a policy-uri this._docRequest = aChannel; - // We will only be able to provide the HTTP version information if aChannel - // implements nsIHttpChannelInternal - if (internalChannel) { - var reqMaj = {}; - var reqMin = {}; - var reqVersion = internalChannel.getRequestVersion(reqMaj, reqMin); - this._request += " HTTP/" + reqMaj.value + "." + reqMin.value; - } + // save the document URI (minus ) and referrer for reporting + let uri = aChannel.URI.cloneIgnoringRef(); + uri.userPass = ''; + this._request = uri.asciiSpec; + + let referrer = aChannel.referrer.cloneIgnoringRef(); + referrer.userPass = ''; + this._referrer = referrer.asciiSpec; }, /* ........ Methods .............. */ @@ -253,27 +247,48 @@ ContentSecurityPolicy.prototype = { * Generates and sends a violation report to the specified report URIs. */ sendReports: - function(blockedUri, violatedDirective, aSourceFile, aScriptSample, aLineNum) { + function(blockedUri, originalUri, violatedDirective, + aSourceFile, aScriptSample, aLineNum) { var uriString = this._policy.getReportURIs(); var uris = uriString.split(/\s+/); if (uris.length > 0) { + // see if we need to sanitize the blocked-uri + let blocked = ''; + if (originalUri) { + // We've redirected, only report the blocked origin + let clone = blockedUri.clone(); + clone.path = ''; + blocked = clone.asciiSpec; + } + else if (blockedUri instanceof Ci.nsIURI) { + blocked = blockedUri.cloneIgnoringRef().asciiSpec; + } + else { + // blockedUri is a string for eval/inline-script violations + blocked = blockedUri; + } + // Generate report to send composed of // { // csp-report: { - // request: "GET /index.html HTTP/1.1", + // document-uri: "http://example.com/file.html?params", + // referrer: "...", // blocked-uri: "...", // violated-directive: "..." // } // } var report = { 'csp-report': { - 'request': this._request, - 'blocked-uri': (blockedUri instanceof Ci.nsIURI ? - blockedUri.asciiSpec : blockedUri), + 'document-uri': this._request, + 'referrer': this._referrer, + 'blocked-uri': blocked, 'violated-directive': violatedDirective } } + // extra report fields for script errors (if available) + if (originalUri) + report["csp-report"]["original-uri"] = originalUri.cloneIgnoringRef().asciiSpec; if (aSourceFile) report["csp-report"]["source-file"] = aSourceFile; if (aScriptSample) @@ -403,7 +418,7 @@ ContentSecurityPolicy.prototype = { ? 'default-src' : 'frame-ancestors ') + directive.toString(); - this._asyncReportViolation(ancestors[i], violatedPolicy); + this._asyncReportViolation(ancestors[i], null, violatedPolicy); // need to lie if we are testing in report-only mode return this._reportOnlyMode; @@ -423,7 +438,7 @@ ContentSecurityPolicy.prototype = { aRequestOrigin, aContext, aMimeTypeGuess, - aExtra) { + aOriginalUri) { // don't filter chrome stuff if (aContentLocation.scheme === 'chrome' || @@ -457,7 +472,7 @@ ContentSecurityPolicy.prototype = { let violatedPolicy = (directive._isImplicit ? 'default-src' : cspContext) + ' ' + directive.toString(); - this._asyncReportViolation(aContentLocation, violatedPolicy); + this._asyncReportViolation(aContentLocation, aOriginalUri, violatedPolicy); } catch(e) { CSPdebug('---------------- ERROR: ' + e); } @@ -487,6 +502,8 @@ ContentSecurityPolicy.prototype = { * @param blockedContentSource * Either a CSP Source (like 'self', as string) or nsIURI: the source * of the violation. + * @param originalUri + * The original URI if the blocked content is a redirect, else null * @param violatedDirective * the directive that was violated (string). * @param observerSubject @@ -500,7 +517,7 @@ ContentSecurityPolicy.prototype = { * source line number of the violation (if available) */ _asyncReportViolation: - function(blockedContentSource, violatedDirective, observerSubject, + function(blockedContentSource, originalUri, violatedDirective, observerSubject, aSourceFile, aScriptSample, aLineNum) { // if optional observerSubject isn't specified, default to the source of // the violation. @@ -523,7 +540,8 @@ ContentSecurityPolicy.prototype = { Services.obs.notifyObservers(observerSubject, CSP_VIOLATION_TOPIC, violatedDirective); - reportSender.sendReports(blockedContentSource, violatedDirective, + reportSender.sendReports(blockedContentSource, originalUri, + violatedDirective, aSourceFile, aScriptSample, aLineNum); }, Ci.nsIThread.DISPATCH_NORMAL); }, diff --git a/content/base/src/nsCSPService.cpp b/content/base/src/nsCSPService.cpp index fc059275071e..470bd2539cd0 100644 --- a/content/base/src/nsCSPService.cpp +++ b/content/base/src/nsCSPService.cpp @@ -96,12 +96,13 @@ CSPService::ShouldLoad(PRUint32 aContentType, NS_ConvertUTF16toUTF8(policy).get())); #endif // obtain the enforcement decision + // (don't pass aExtra, we use that slot for redirects) csp->ShouldLoad(aContentType, aContentLocation, aRequestOrigin, aRequestContext, aMimeTypeGuess, - aExtra, + nsnull, aDecision); } } @@ -220,13 +221,15 @@ CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel, // If not, cancel the load now. nsCOMPtr newUri; newChannel->GetURI(getter_AddRefs(newUri)); + nsCOMPtr originalUri; + oldChannel->GetOriginalURI(getter_AddRefs(originalUri)); PRInt16 aDecision = nsIContentPolicy::ACCEPT; csp->ShouldLoad(loadType, // load type per nsIContentPolicy (PRUint32) newUri, // nsIURI nsnull, // nsIURI nsnull, // nsISupports EmptyCString(), // ACString - MIME guess - nsnull, // nsISupports - extra + originalUri, // nsISupports - extra &aDecision); #ifdef PR_LOGGING diff --git a/content/base/test/test_bug548193.html b/content/base/test/test_bug548193.html index 9538d54a7616..fa8726ef33ef 100644 --- a/content/base/test/test_bug548193.html +++ b/content/base/test/test_bug548193.html @@ -82,8 +82,8 @@ var testFile = "file_bug548193.sjs"; window.checkResults = function(reportObj) { var cspReport = reportObj["csp-report"]; // correct violating request - is(cspReport["request"], - "GET http://mochi.test:8888/tests/content/base/test/" + testFile + " HTTP/1.1", + is(cspReport["document-uri"], + "http://mochi.test:8888/tests/content/base/test/" + testFile, "Incorrect violating request"); // correct blocked-uri is(cspReport["blocked-uri"],