bug 767778 bring report struct in-line w/1.0 spec; include original URI for redirects r=sstamm, a=akeybl

This commit is contained in:
Daniel Veditz 2012-07-10 00:44:05 -07:00
parent 225d52918d
commit b90bac7d50
3 changed files with 53 additions and 32 deletions

View File

@ -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 <fragment>) 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);
},

View File

@ -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<nsIURI> newUri;
newChannel->GetURI(getter_AddRefs(newUri));
nsCOMPtr<nsIURI> 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

View File

@ -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"],