зеркало из https://github.com/mozilla/gecko-dev.git
Bug 911547 - make nsIContentSecurityPolicy serializable and trigger read/write from nsPrincipal. r=jst,grobinson
--HG-- extra : rebase_source : 3e1846e15538729f3c94f5c1470959b5d7b31f0f
This commit is contained in:
Родитель
499b09923b
Коммит
f6b4704ae8
|
@ -491,9 +491,22 @@ nsPrincipal::Read(nsIObjectInputStream* aStream)
|
|||
rv = aStream->ReadBoolean(&inMozBrowser);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = Init(codebase, appId, inMozBrowser);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// need to link in the CSP context here (link in a reference to this
|
||||
// nsIPrincipal and to the URI of the protected resource).
|
||||
if (csp) {
|
||||
csp->SetRequestContext(codebase, nullptr, this, nullptr);
|
||||
}
|
||||
|
||||
SetDomain(domain);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -519,6 +532,13 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream)
|
|||
aStream->Write32(mAppId);
|
||||
aStream->WriteBoolean(mInMozBrowser);
|
||||
|
||||
rv = NS_WriteOptionalCompoundObject(aStream, mCSP,
|
||||
NS_GET_IID(nsIContentSecurityPolicy),
|
||||
true);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// mCodebaseImmutable and mDomainImmutable will be recomputed based
|
||||
// on the deserialized URIs in Read().
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsISerializable.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIChannel;
|
||||
interface nsIDocShell;
|
||||
interface nsIPrincipal;
|
||||
|
||||
/**
|
||||
* nsIContentSecurityPolicy
|
||||
|
@ -15,8 +16,8 @@ interface nsIDocShell;
|
|||
* one of these per document/principal.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(2e7875a3-8cb5-4ebb-905b-af0a90dae594)]
|
||||
interface nsIContentSecurityPolicy : nsISupports
|
||||
[scriptable, uuid(8b91f829-b1bf-4327-8ece-4000aa823394)]
|
||||
interface nsIContentSecurityPolicy : nsISerializable
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -180,10 +181,18 @@ interface nsIContentSecurityPolicy : nsISupports
|
|||
const unsigned short VIOLATION_TYPE_HASH_STYLE = 7;
|
||||
|
||||
/**
|
||||
* Called after the CSP object is created to fill in the appropriate request
|
||||
* and request header information needed in case a report needs to be sent.
|
||||
* Called after the CSP object is created to fill in appropriate request
|
||||
* context and give it a reference to its owning principal for violation
|
||||
* report generation.
|
||||
* This will use whatever data is available, choosing earlier arguments first
|
||||
* if multiple are available. Either way, it will attempt to obtain the URI,
|
||||
* referrer and the principal from whatever is available. If the channel is
|
||||
* available, it'll also store that for processing policy-uri directives.
|
||||
*/
|
||||
void scanRequestData(in nsIChannel aChannel);
|
||||
void setRequestContext(in nsIURI selfURI,
|
||||
in nsIURI referrer,
|
||||
in nsIPrincipal documentPrincipal,
|
||||
in nsIChannel aChannel);
|
||||
|
||||
/**
|
||||
* Verifies ancestry as permitted by the policy.
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
* that ContentSecurityPolicy has to do.
|
||||
*/
|
||||
|
||||
// these identifiers are also defined in contentSecurityPolicy.manifest.
|
||||
const CSP_CLASS_ID = Components.ID("{d1680bb4-1ac0-4772-9437-1188375e44f2}");
|
||||
const CSP_CONTRACT_ID = "@mozilla.org/contentsecuritypolicy;1";
|
||||
|
||||
/* :::::::: Constants and Helpers ::::::::::::::: */
|
||||
|
||||
const Cc = Components.classes;
|
||||
|
@ -123,8 +127,17 @@ function ContentSecurityPolicy() {
|
|||
}
|
||||
|
||||
ContentSecurityPolicy.prototype = {
|
||||
classID: Components.ID("{d1680bb4-1ac0-4772-9437-1188375e44f2}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentSecurityPolicy]),
|
||||
classID: CSP_CLASS_ID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentSecurityPolicy,
|
||||
Ci.nsISerializable,
|
||||
Ci.nsISupports]),
|
||||
|
||||
// Class info is required to be able to serialize
|
||||
classInfo: XPCOMUtils.generateCI({classID: CSP_CLASS_ID,
|
||||
contractID: CSP_CONTRACT_ID,
|
||||
interfaces: [Ci.nsIContentSecurityPolicy,
|
||||
Ci.nsISerializable],
|
||||
flags: Ci.nsIClassInfo.MAIN_THREAD_ONLY}),
|
||||
|
||||
get isInitialized() {
|
||||
return this._isInitialized;
|
||||
|
@ -343,28 +356,45 @@ ContentSecurityPolicy.prototype = {
|
|||
/**
|
||||
* Given an nsIHttpChannel, fill out the appropriate data.
|
||||
*/
|
||||
scanRequestData:
|
||||
function(aChannel) {
|
||||
if (!aChannel)
|
||||
setRequestContext:
|
||||
function(aSelfURI, aReferrerURI, aPrincipal, aChannel) {
|
||||
|
||||
// this requires either a self URI or a http channel.
|
||||
if (!aSelfURI && !aChannel)
|
||||
return;
|
||||
|
||||
// Save the docRequest for fetching a policy-uri
|
||||
this._weakDocRequest = Cu.getWeakReference(aChannel);
|
||||
if (aChannel) {
|
||||
// Save the docRequest for fetching a policy-uri
|
||||
this._weakDocRequest = Cu.getWeakReference(aChannel);
|
||||
}
|
||||
|
||||
// save the document URI (minus <fragment>) and referrer for reporting
|
||||
let uri = aChannel.URI.cloneIgnoringRef();
|
||||
let uri = aSelfURI ? aSelfURI.cloneIgnoringRef() : aChannel.URI.cloneIgnoringRef();
|
||||
try { // GetUserPass throws for some protocols without userPass
|
||||
uri.userPass = '';
|
||||
} catch (ex) {}
|
||||
this._request = uri.asciiSpec;
|
||||
this._requestOrigin = uri;
|
||||
|
||||
//store a reference to the principal, that can later be used in shouldLoad
|
||||
this._weakRequestPrincipal = Cu.getWeakReference(Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager)
|
||||
.getChannelPrincipal(aChannel));
|
||||
// store a reference to the principal, that can later be used in shouldLoad
|
||||
if (aPrincipal) {
|
||||
this._weakRequestPrincipal = Cu.getWeakReference(aPrincipal);
|
||||
} else if (aChannel) {
|
||||
this._weakRequestPrincipal = Cu.getWeakReference(Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager)
|
||||
.getChannelPrincipal(aChannel));
|
||||
} else {
|
||||
CSPdebug("No principal or channel for document context; violation reports may not work.");
|
||||
}
|
||||
|
||||
if (aChannel instanceof Ci.nsIHttpChannel && aChannel.referrer) {
|
||||
// pick one: referrerURI, channel's referrer, or null (first available)
|
||||
let ref = null;
|
||||
if (aReferrerURI)
|
||||
ref = aReferrerURI;
|
||||
else if (aChannel instanceof Ci.nsIHttpChannel)
|
||||
ref = aChannel.referrer;
|
||||
|
||||
if (ref) {
|
||||
let referrer = aChannel.referrer.cloneIgnoringRef();
|
||||
try { // GetUserPass throws for some protocols without userPass
|
||||
referrer.userPass = '';
|
||||
|
@ -383,7 +413,7 @@ ContentSecurityPolicy.prototype = {
|
|||
function csp_appendPolicy(aPolicy, selfURI, aReportOnly, aSpecCompliant) {
|
||||
#ifndef MOZ_B2G
|
||||
CSPdebug("APPENDING POLICY: " + aPolicy);
|
||||
CSPdebug(" SELF: " + selfURI.asciiSpec);
|
||||
CSPdebug(" SELF: " + (selfURI ? selfURI.asciiSpec : " null"));
|
||||
CSPdebug("CSP 1.0 COMPLIANT : " + aSpecCompliant);
|
||||
#endif
|
||||
|
||||
|
@ -905,6 +935,51 @@ ContentSecurityPolicy.prototype = {
|
|||
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
},
|
||||
|
||||
/* ........ nsISerializable Methods: .............. */
|
||||
|
||||
read:
|
||||
function(aStream) {
|
||||
|
||||
this._requestOrigin = aStream.readObject(true);
|
||||
this._requestOrigin.QueryInterface(Ci.nsIURI);
|
||||
|
||||
for (let pCount = aStream.read32(); pCount > 0; pCount--) {
|
||||
let polStr = aStream.readString();
|
||||
let reportOnly = aStream.readBoolean();
|
||||
let specCompliant = aStream.readBoolean();
|
||||
// don't need self info because when the policy is turned back into a
|
||||
// string, 'self' is replaced with the explicit source expression.
|
||||
this.appendPolicy(polStr, null, reportOnly, specCompliant);
|
||||
}
|
||||
|
||||
// NOTE: the document instance that's deserializing this object (via its
|
||||
// principal) should hook itself into this._principal manually. If they
|
||||
// don't, the CSP reports will likely be blocked by nsMixedContentBlocker.
|
||||
},
|
||||
|
||||
write:
|
||||
function(aStream) {
|
||||
// need to serialize the context: request origin and such. They are
|
||||
// used when sending reports. Since _request and _requestOrigin are just
|
||||
// different representations of the same thing, only save _requestOrigin
|
||||
// (an nsIURI).
|
||||
aStream.writeCompoundObject(this._requestOrigin, Ci.nsIURI, true);
|
||||
|
||||
// we can't serialize a reference to the principal that triggered this
|
||||
// instance to serialize, so when this is deserialized by the principal the
|
||||
// caller must hook it up manually by calling setRequestContext on this
|
||||
// instance with the appropriate nsIChannel.
|
||||
|
||||
// Finally, serialize all the policies.
|
||||
aStream.write32(this._policies.length);
|
||||
|
||||
for each (var policy in this._policies) {
|
||||
aStream.writeWStringZ(policy.toString());
|
||||
aStream.writeBoolean(policy._reportOnlyMode);
|
||||
aStream.writeBoolean(policy._specCompliant);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// The POST of the violation report (if it happens) should not follow
|
||||
|
|
|
@ -2691,7 +2691,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
|||
aChannel->GetURI(getter_AddRefs(selfURI));
|
||||
|
||||
// Store the request context for violation reports
|
||||
csp->ScanRequestData(aChannel);
|
||||
csp->SetRequestContext(nullptr, nullptr, nullptr, aChannel);
|
||||
|
||||
// ----- if the doc is an app and we want a default CSP, apply it.
|
||||
if (applyAppDefaultCSP) {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<script type="application/javascript;version=1.8">
|
||||
"use strict";
|
||||
|
||||
// Ensure that `scanRequestData` doesn't throw with app:// URLs
|
||||
// Ensure that `setRequestContext` doesn't throw with app:// URLs
|
||||
|
||||
const csp = SpecialPowers.Cc["@mozilla.org/contentsecuritypolicy;1"]
|
||||
.createInstance(SpecialPowers.Ci.nsIContentSecurityPolicy);
|
||||
|
@ -44,10 +44,10 @@
|
|||
let appchan = SpecialPowers.Services.io.newChannel(gManifestURL, null, null);
|
||||
|
||||
try {
|
||||
csp.scanRequestData(appchan);
|
||||
ok(true, "scanRequestData hasn't thown");
|
||||
csp.setRequestContext(null, null, null, appchan);
|
||||
ok(true, "setRequestContext hasn't thown");
|
||||
} catch(e) {
|
||||
ok(false, "scanRequestData throws");
|
||||
ok(false, "setRequestContext throws");
|
||||
}
|
||||
|
||||
cleanup()
|
||||
|
|
|
@ -76,7 +76,7 @@ function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) {
|
|||
dump("Created test " + id + " : " + policy + "\n\n");
|
||||
|
||||
// make the reports seem authentic by "binding" them to a channel.
|
||||
csp.scanRequestData(selfchan);
|
||||
csp.setRequestContext(selfuri, null, null, selfchan);
|
||||
|
||||
// Load up the policy
|
||||
// set as report-only if that's the case
|
||||
|
|
Загрузка…
Ссылка в новой задаче