--- a/content/base/src/contentSecurityPolicy.js
+++ b/content/base/src/contentSecurityPolicy.js
@@ -32,17 +32,16 @@ function ContentSecurityPolicy() {
this._reportOnlyMode = false;
this._policy = CSPRep.fromString("default-src *");
// default options "wide open" since this policy will be intersected soon
this._policy._allowInlineScripts = true;
this._policy._allowEval = true;
this._request = "";
- this._referrer = "";
this._docRequest = null;
CSPdebug("CSP POLICY INITED TO 'default-src *'");
}
/*
* Set up mappings from nsIContentPolicy content types to CSP directives.
*/
{
@@ -148,23 +147,23 @@ ContentSecurityPolicy.prototype = {
logViolationDetails:
function(aViolationType, aSourceFile, aScriptSample, aLineNum) {
// allowsInlineScript and allowsEval both return true when report-only mode
// is enabled, resulting in a call to this function. Therefore we need to
// check that the policy was in fact violated before logging any violations
switch (aViolationType) {
case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_SCRIPT:
if (!this._policy.allowsInlineScripts)
- this._asyncReportViolation('self',null,'inline script base restriction',
+ this._asyncReportViolation('self','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',null,'eval script base restriction',
+ this._asyncReportViolation('self','eval script base restriction',
'violated base restriction: Code will not be created from strings',
aSourceFile, aScriptSample, aLineNum);
break;
}
},
set reportOnlyMode(val) {
this._reportOnlyMode = val;
@@ -184,28 +183,35 @@ ContentSecurityPolicy.prototype = {
/**
* Given an nsIHttpChannel, fill out the appropriate data.
*/
scanRequestData:
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);
+ }
- // Save the docRequest for fetching a policy-uri
+ this._request = aChannel.requestMethod + " " + aChannel.URI.asciiSpec;
this._docRequest = aChannel;
- // 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;
+ // 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;
+ }
},
/* ........ Methods .............. */
/**
* Given a new policy, intersects the currently enforced policy with the new
* one and stores the result. The effect is a "tightening" or refinement of
* an old policy. This is called any time a new policy is encountered and
@@ -242,58 +248,37 @@ ContentSecurityPolicy.prototype = {
this._policy = intersect;
this._isInitialized = true;
},
/**
* Generates and sends a violation report to the specified report URIs.
*/
sendReports:
- function(blockedUri, originalUri, violatedDirective,
- aSourceFile, aScriptSample, aLineNum) {
+ function(blockedUri, 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: {
- // document-uri: "http://example.com/file.html?params",
- // referrer: "...",
+ // request: "GET /index.html HTTP/1.1",
// blocked-uri: "...",
// violated-directive: "..."
// }
// }
var report = {
'csp-report': {
- 'document-uri': this._request,
- 'referrer': this._referrer,
- 'blocked-uri': blocked,
+ 'request': this._request,
+ 'blocked-uri': (blockedUri instanceof Ci.nsIURI ?
+ blockedUri.asciiSpec : blockedUri),
'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)
report["csp-report"]["script-sample"] = aScriptSample;
if (aLineNum)
report["csp-report"]["line-number"] = aLineNum;
var reportString = JSON.stringify(report);
@@ -413,17 +398,17 @@ ContentSecurityPolicy.prototype = {
let ancestor = ancestors[i].prePath;
if (!this._policy.permits(ancestor, cspContext)) {
// report the frame-ancestor violation
let directive = this._policy._directives[cspContext];
let violatedPolicy = (directive._isImplicit
? 'default-src' : 'frame-ancestors ')
+ directive.toString();
- this._asyncReportViolation(ancestors[i], null, violatedPolicy);
+ this._asyncReportViolation(ancestors[i], violatedPolicy);
// need to lie if we are testing in report-only mode
return this._reportOnlyMode;
}
}
return true;
},
@@ -433,17 +418,17 @@ ContentSecurityPolicy.prototype = {
* decides whether or not the policy is satisfied.
*/
shouldLoad:
function csp_shouldLoad(aContentType,
aContentLocation,
aRequestOrigin,
aContext,
aMimeTypeGuess,
- aOriginalUri) {
+ aExtra) {
// don't filter chrome stuff
if (aContentLocation.scheme === 'chrome' ||
aContentLocation.scheme === 'resource') {
return Ci.nsIContentPolicy.ACCEPT;
}
// interpret the context, and then pass off to the decision structure
@@ -467,17 +452,17 @@ ContentSecurityPolicy.prototype = {
// If the result is *NOT* ACCEPT, then send report
if (res != Ci.nsIContentPolicy.ACCEPT) {
CSPdebug("blocking request for " + aContentLocation.asciiSpec);
try {
let directive = this._policy._directives[cspContext];
let violatedPolicy = (directive._isImplicit
? 'default-src' : cspContext)
+ ' ' + directive.toString();
- this._asyncReportViolation(aContentLocation, aOriginalUri, violatedPolicy);
+ this._asyncReportViolation(aContentLocation, violatedPolicy);
} catch(e) {
CSPdebug('---------------- ERROR: ' + e);
}
}
return (this._reportOnlyMode ? Ci.nsIContentPolicy.ACCEPT : res);
},
@@ -497,32 +482,30 @@ ContentSecurityPolicy.prototype = {
/**
* Asynchronously notifies any nsIObservers listening to the CSP violation
* topic that a violation occurred. Also triggers report sending. All
* asynchronous on the main thread.
*
* @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
* optional, subject sent to the nsIObservers listening to the CSP
* violation topic.
* @param aSourceFile
* name of the file containing the inline script violation
* @param aScriptSample
* a sample of the violating inline script
* @param aLineNum
* source line number of the violation (if available)
*/
_asyncReportViolation:
- function(blockedContentSource, originalUri, violatedDirective, observerSubject,
+ function(blockedContentSource, violatedDirective, observerSubject,
aSourceFile, aScriptSample, aLineNum) {
// if optional observerSubject isn't specified, default to the source of
// the violation.
if (!observerSubject)
observerSubject = blockedContentSource;
// gotta wrap things that aren't nsISupports, since it's sent out to
// observers as such. Objects that are not nsISupports are converted to
@@ -535,18 +518,17 @@ ContentSecurityPolicy.prototype = {
}
var reportSender = this;
Services.tm.mainThread.dispatch(
function() {
Services.obs.notifyObservers(observerSubject,
CSP_VIOLATION_TOPIC,
violatedDirective);
- reportSender.sendReports(blockedContentSource, originalUri,
- violatedDirective,
+ reportSender.sendReports(blockedContentSource, violatedDirective,
aSourceFile, aScriptSample, aLineNum);
}, Ci.nsIThread.DISPATCH_NORMAL);
},
};
// The POST of the violation report (if it happens) should not follow
// redirects, per the spec. hence, we implement an nsIChannelEventSink
// with an object so we can tell XHR to abort if a redirect happens.
--- a/content/base/src/nsCSPService.cpp
+++ b/content/base/src/nsCSPService.cpp
@@ -91,23 +91,22 @@ CSPService::ShouldLoad(PRUint32 aContent
#ifdef PR_LOGGING
nsAutoString policy;
csp->GetPolicy(policy);
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
("Document has CSP: %s",
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,
- nsnull,
+ aExtra,
aDecision);
}
}
#ifdef PR_LOGGING
else {
nsCAutoString uriSpec;
aContentLocation->GetSpec(uriSpec);
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
@@ -216,25 +215,23 @@ CSPService::AsyncOnChannelRedirect(nsICh
* the new channel's property bag. This container is propagated forward when
* channels redirect.
*/
// Does the CSP permit this host for this type of load?
// 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
- originalUri, // nsISupports - extra
+ nsnull, // nsISupports - extra
&aDecision);
#ifdef PR_LOGGING
if (newUri) {
nsCAutoString newUriSpec("None");
newUri->GetSpec(newUriSpec);
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
("CSPService::AsyncOnChannelRedirect called for %s",