Bug 1139297 - Implement CSP upgrade-insecure-requests directive - csp changes (r=sstamm)

This commit is contained in:
Christoph Kerschbaumer 2015-07-10 09:13:54 -07:00
parent 51b48936c3
commit 12f19dc2be
6 changed files with 258 additions and 98 deletions

View File

@ -20,7 +20,7 @@ interface nsIURI;
typedef unsigned short CSPDirective;
[scriptable, uuid(059b94e3-45c2-4794-ac2a-5b66a66b5967)]
[scriptable, uuid(b622b0f8-ee51-4f7a-8c23-b3bce20e752e)]
interface nsIContentSecurityPolicy : nsISerializable
{
/**
@ -32,23 +32,24 @@ interface nsIContentSecurityPolicy : nsISerializable
* NOTE: When implementing a new directive, you will need to add it here but also
* add it to the CSPStrDirectives array in nsCSPUtils.h.
*/
const unsigned short NO_DIRECTIVE = 0;
const unsigned short DEFAULT_SRC_DIRECTIVE = 1;
const unsigned short SCRIPT_SRC_DIRECTIVE = 2;
const unsigned short OBJECT_SRC_DIRECTIVE = 3;
const unsigned short STYLE_SRC_DIRECTIVE = 4;
const unsigned short IMG_SRC_DIRECTIVE = 5;
const unsigned short MEDIA_SRC_DIRECTIVE = 6;
const unsigned short FRAME_SRC_DIRECTIVE = 7;
const unsigned short FONT_SRC_DIRECTIVE = 8;
const unsigned short CONNECT_SRC_DIRECTIVE = 9;
const unsigned short REPORT_URI_DIRECTIVE = 10;
const unsigned short FRAME_ANCESTORS_DIRECTIVE = 11;
const unsigned short REFLECTED_XSS_DIRECTIVE = 12;
const unsigned short BASE_URI_DIRECTIVE = 13;
const unsigned short FORM_ACTION_DIRECTIVE = 14;
const unsigned short REFERRER_DIRECTIVE = 15;
const unsigned short WEB_MANIFEST_SRC_DIRECTIVE = 16;
const unsigned short NO_DIRECTIVE = 0;
const unsigned short DEFAULT_SRC_DIRECTIVE = 1;
const unsigned short SCRIPT_SRC_DIRECTIVE = 2;
const unsigned short OBJECT_SRC_DIRECTIVE = 3;
const unsigned short STYLE_SRC_DIRECTIVE = 4;
const unsigned short IMG_SRC_DIRECTIVE = 5;
const unsigned short MEDIA_SRC_DIRECTIVE = 6;
const unsigned short FRAME_SRC_DIRECTIVE = 7;
const unsigned short FONT_SRC_DIRECTIVE = 8;
const unsigned short CONNECT_SRC_DIRECTIVE = 9;
const unsigned short REPORT_URI_DIRECTIVE = 10;
const unsigned short FRAME_ANCESTORS_DIRECTIVE = 11;
const unsigned short REFLECTED_XSS_DIRECTIVE = 12;
const unsigned short BASE_URI_DIRECTIVE = 13;
const unsigned short FORM_ACTION_DIRECTIVE = 14;
const unsigned short REFERRER_DIRECTIVE = 15;
const unsigned short WEB_MANIFEST_SRC_DIRECTIVE = 16;
const unsigned short UPGRADE_IF_INSECURE_DIRECTIVE = 17;
/**
* Accessor method for a read-only string version of the policy at a given
@ -62,6 +63,13 @@ interface nsIContentSecurityPolicy : nsISerializable
*/
readonly attribute unsigned long policyCount;
/**
* Returns whether this policy uses the directive upgrade-insecure-requests.
* Please note that upgrade-insecure-reqeusts also applies if the parent or
* including document (context) makes use of the directive.
*/
readonly attribute bool upgradeInsecureRequests;
/**
* Obtains the referrer policy (as integer) for this browsing context as
* specified in CSP. If there are multiple policies and...

View File

@ -54,6 +54,11 @@ inlineStyleBlocked = An attempt to apply inline style sheets has been blocked
# LOCALIZATION NOTE (scriptFromStringBlocked):
# eval is a name and should not be localized.
scriptFromStringBlocked = An attempt to call JavaScript from a string (by calling a function like eval) has been blocked
# LOCALIZATION NOTE (upgradeInsecureRequest):
# %1$S is the URL of the upgraded request; %2$S is the upgraded scheme.
upgradeInsecureRequest = Upgrading insecure request '%1$S' to use '%2$S'
# LOCALIZATION NOTE (ignoreSrcForDirective):
ignoreSrcForDirective = Ignoring srcs for directive '%1$S'
# LOCALIZATION NOTE (hostNameMightBeKeyword):
# %1$S is the hostname in question and %2$S is the keyword
hostNameMightBeKeyword = Interpreting %1$S as a hostname, not a keyword. If you intended this to be a keyword, use '%2$S' (wrapped in single quotes).

View File

@ -304,6 +304,19 @@ nsCSPContext::GetPolicyCount(uint32_t *outPolicyCount)
return NS_OK;
}
NS_IMETHODIMP
nsCSPContext::GetUpgradeInsecureRequests(bool *outUpgradeRequest)
{
*outUpgradeRequest = false;
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
if (mPolicies[i]->hasDirective(nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
*outUpgradeRequest = true;
return NS_OK;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsCSPContext::GetReferrerPolicy(uint32_t* outPolicy, bool* outIsSet)
{

View File

@ -804,10 +804,7 @@ nsCSPParser::sourceExpression()
resetCurValue();
// If mCurToken does not provide a scheme (scheme-less source), we apply the scheme
// from selfURI but we also need to remember if the protected resource is http, in
// which case we should allow https loads, see:
// http://www.w3.org/TR/CSP2/#match-source-expression
bool allowHttps = false;
// from selfURI
if (parsedScheme.IsEmpty()) {
// Resetting internal helpers, because we might already have parsed some of the host
// when trying to parse a scheme.
@ -815,14 +812,13 @@ nsCSPParser::sourceExpression()
nsAutoCString selfScheme;
mSelfURI->GetScheme(selfScheme);
parsedScheme.AssignASCII(selfScheme.get());
allowHttps = selfScheme.EqualsASCII("http");
}
// At this point we are expecting a host to be parsed.
// Trying to create a new nsCSPHost.
if (nsCSPHostSrc *cspHost = hostSource()) {
// Do not forget to set the parsed scheme.
cspHost->setScheme(parsedScheme, allowHttps);
cspHost->setScheme(parsedScheme);
return cspHost;
}
// Error was reported in hostSource()
@ -992,6 +988,12 @@ nsCSPParser::directiveName()
params, ArrayLength(params));
return nullptr;
}
// special case handling for upgrade-insecure-requests
if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
return new nsUpgradeInsecureDirective(CSP_StringToCSPDirective(mCurToken));
}
return new nsCSPDirective(CSP_StringToCSPDirective(mCurToken));
}
@ -1023,6 +1025,20 @@ nsCSPParser::directive()
return;
}
// special case handling for upgrade-insecure-requests, which is only specified
// by a directive name but does not include any srcs.
if (cspDir->equals(nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE)) {
if (mCurDir.Length() > 1) {
const char16_t* params[] = { NS_LITERAL_STRING("upgrade-insecure-requests").get() };
logWarningErrorToConsole(nsIScriptError::warningFlag,
"ignoreSrcForDirective",
params, ArrayLength(params));
}
// add the directive and return
mPolicy->addUpgradeInsecDir(static_cast<nsUpgradeInsecureDirective*>(cspDir));
return;
}
// make sure to reset cache variables when trying to invalidate unsafe-inline;
// unsafe-inline might not only appear in script-src, but also in default-src
mHasHashOrNonce = false;

View File

@ -255,6 +255,59 @@ CSP_IsQuotelessKeyword(const nsAString& aKey)
return false;
}
/*
* Checks whether the current directive permits a specific
* scheme. This function is called from nsCSPSchemeSrc() and
* also nsCSPHostSrc.
* @param aEnforcementScheme
* The scheme that this directive allows
* @param aUri
* The uri of the subresource load.
* @param aReportOnly
* Whether the enforced policy is report only or not.
* @param aUpgradeInsecure
* Whether the policy makes use of the directive
* 'upgrade-insecure-requests'.
*/
bool
permitsScheme(const nsAString& aEnforcementScheme,
nsIURI* aUri,
bool aReportOnly,
bool aUpgradeInsecure)
{
nsAutoCString scheme;
nsresult rv = aUri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, false);
// no scheme to enforce, let's allow the load (e.g. script-src *)
if (aEnforcementScheme.IsEmpty()) {
return true;
}
// if the scheme matches, all good - allow the load
if (aEnforcementScheme.EqualsASCII(scheme.get())) {
return true;
}
// allow scheme-less sources where the protected resource is http
// and the load is https, see:
// http://www.w3.org/TR/CSP2/#match-source-expression
if (aEnforcementScheme.EqualsASCII("http") &&
scheme.EqualsASCII("https")) {
return true;
}
// Allow the load when enforcing upgrade-insecure-requests with the
// promise the request gets upgraded from http to https and ws to wss.
// See nsHttpChannel::Connect() and also WebSocket.cpp. Please note,
// the report only policies should not allow the load and report
// the error back to the page.
return ((aUpgradeInsecure && !aReportOnly) &&
((scheme.EqualsASCII("http") && aEnforcementScheme.EqualsASCII("https")) ||
(scheme.EqualsASCII("ws") && aEnforcementScheme.EqualsASCII("wss"))));
}
/* ===== nsCSPSrc ============================ */
nsCSPBaseSrc::nsCSPBaseSrc()
@ -269,7 +322,8 @@ nsCSPBaseSrc::~nsCSPBaseSrc()
// nsCSPKeywordSrc and nsCSPHashSource fall back to this base class
// implementation which will never allow the load.
bool
nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
nsCSPBaseSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const
{
if (CSPUTILSLOGENABLED()) {
nsAutoCString spec;
@ -304,19 +358,16 @@ nsCSPSchemeSrc::~nsCSPSchemeSrc()
}
bool
nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
nsCSPSchemeSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const
{
if (CSPUTILSLOGENABLED()) {
nsAutoCString spec;
aUri->GetSpec(spec);
CSPUTILSLOG(("nsCSPSchemeSrc::permits, aUri: %s", spec.get()));
}
NS_ASSERTION((!mScheme.EqualsASCII("")), "scheme can not be the empty string");
nsAutoCString scheme;
nsresult rv = aUri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, false);
return mScheme.EqualsASCII(scheme.get());
MOZ_ASSERT((!mScheme.EqualsASCII("")), "scheme can not be the empty string");
return permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure);
}
void
@ -330,7 +381,6 @@ nsCSPSchemeSrc::toString(nsAString& outStr) const
nsCSPHostSrc::nsCSPHostSrc(const nsAString& aHost)
: mHost(aHost)
, mAllowHttps(false)
{
ToLowerCase(mHost);
}
@ -340,7 +390,8 @@ nsCSPHostSrc::~nsCSPHostSrc()
}
bool
nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const
{
if (CSPUTILSLOGENABLED()) {
nsAutoCString spec;
@ -352,21 +403,8 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
// http://www.w3.org/TR/CSP11/#match-source-expression
// 4.3) scheme matching: Check if the scheme matches.
nsAutoCString scheme;
nsresult rv = aUri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, false);
if (!mScheme.IsEmpty() &&
!mScheme.EqualsASCII(scheme.get())) {
// We should not return false for scheme-less sources where the protected resource
// is http and the load is https, see:
// http://www.w3.org/TR/CSP2/#match-source-expression
bool isHttpsScheme =
(NS_SUCCEEDED(aUri->SchemeIs("https", &isHttpsScheme)) && isHttpsScheme);
if (!(isHttpsScheme && mAllowHttps)) {
return false;
}
if (!permitsScheme(mScheme, aUri, aReportOnly, aUpgradeInsecure)) {
return false;
}
// The host in nsCSpHostSrc should never be empty. In case we are enforcing
@ -396,7 +434,7 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
// Before we can check if the host matches, we have to
// extract the host part from aUri.
nsAutoCString uriHost;
rv = aUri->GetHost(uriHost);
nsresult rv = aUri->GetHost(uriHost);
NS_ENSURE_SUCCESS(rv, false);
// 4.5) host matching: Check if the allowed host starts with a wilcard.
@ -458,6 +496,11 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
int32_t uriPort;
rv = aUri->GetPort(&uriPort);
NS_ENSURE_SUCCESS(rv, false);
nsAutoCString scheme;
rv = aUri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, false);
uriPort = (uriPort > 0) ? uriPort : NS_GetDefaultPort(scheme.get());
// 4.7) Default port matching: If mPort is empty, we have to compare default ports.
@ -468,7 +511,7 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
// is http and the load is https, see: http://www.w3.org/TR/CSP2/#match-source-expression
// BUT, we only allow scheme-less sources to be upgraded from http to https if CSP
// does not explicitly define a port.
if (!(uriPort == NS_GetDefaultPort("https") && mAllowHttps)) {
if (!(uriPort == NS_GetDefaultPort("https"))) {
return false;
}
}
@ -515,11 +558,10 @@ nsCSPHostSrc::toString(nsAString& outStr) const
}
void
nsCSPHostSrc::setScheme(const nsAString& aScheme, bool aAllowHttps)
nsCSPHostSrc::setScheme(const nsAString& aScheme)
{
mScheme = aScheme;
ToLowerCase(mScheme);
mAllowHttps = aAllowHttps;
}
void
@ -590,7 +632,8 @@ nsCSPNonceSrc::~nsCSPNonceSrc()
}
bool
nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
nsCSPNonceSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const
{
if (CSPUTILSLOGENABLED()) {
nsAutoCString spec;
@ -718,7 +761,8 @@ nsCSPDirective::~nsCSPDirective()
}
bool
nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const
nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const
{
if (CSPUTILSLOGENABLED()) {
nsAutoCString spec;
@ -727,20 +771,13 @@ nsCSPDirective::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirect
}
for (uint32_t i = 0; i < mSrcs.Length(); i++) {
if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected)) {
if (mSrcs[i]->permits(aUri, aNonce, aWasRedirected, aReportOnly, aUpgradeInsecure)) {
return true;
}
}
return false;
}
bool
nsCSPDirective::permits(nsIURI* aUri) const
{
nsString dummyNonce;
return permits(aUri, dummyNonce, false);
}
bool
nsCSPDirective::allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
{
@ -887,10 +924,29 @@ nsCSPDirective::getReportURIs(nsTArray<nsString> &outReportURIs) const
}
}
/* =============== nsUpgradeInsecureDirective ============= */
nsUpgradeInsecureDirective::nsUpgradeInsecureDirective(CSPDirective aDirective)
: nsCSPDirective(aDirective)
{
}
nsUpgradeInsecureDirective::~nsUpgradeInsecureDirective()
{
}
void
nsUpgradeInsecureDirective::toString(nsAString& outStr) const
{
outStr.AppendASCII(CSP_CSPDirectiveToString(
nsIContentSecurityPolicy::UPGRADE_IF_INSECURE_DIRECTIVE));
}
/* ===== nsCSPPolicy ========================= */
nsCSPPolicy::nsCSPPolicy()
: mReportOnly(false)
: mUpgradeInsecDir(nullptr)
, mReportOnly(false)
{
CSPUTILSLOG(("nsCSPPolicy::nsCSPPolicy"));
}
@ -936,7 +992,7 @@ nsCSPPolicy::permits(CSPDirective aDir,
// These directive arrays are short (1-5 elements), not worth using a hashtable.
for (uint32_t i = 0; i < mDirectives.Length(); i++) {
if (mDirectives[i]->equals(aDir)) {
if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected)) {
if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected, mReportOnly, mUpgradeInsecDir)) {
mDirectives[i]->toString(outViolatedDirective);
return false;
}
@ -950,7 +1006,7 @@ nsCSPPolicy::permits(CSPDirective aDir,
// If the above loop runs through, we haven't found a matching directive.
// Avoid relooping, just store the result of default-src while looping.
if (!aSpecific && defaultDir) {
if (!defaultDir->permits(aUri, aNonce, aWasRedirected)) {
if (!defaultDir->permits(aUri, aNonce, aWasRedirected, mReportOnly, mUpgradeInsecDir)) {
defaultDir->toString(outViolatedDirective);
return false;
}

View File

@ -70,23 +70,24 @@ void CSP_LogMessage(const nsAString& aMessage,
// Order of elements below important! Make sure it matches the order as in
// nsIContentSecurityPolicy.idl
static const char* CSPStrDirectives[] = {
"-error-", // NO_DIRECTIVE
"default-src", // DEFAULT_SRC_DIRECTIVE
"script-src", // SCRIPT_SRC_DIRECTIVE
"object-src", // OBJECT_SRC_DIRECTIVE
"style-src", // STYLE_SRC_DIRECTIVE
"img-src", // IMG_SRC_DIRECTIVE
"media-src", // MEDIA_SRC_DIRECTIVE
"frame-src", // FRAME_SRC_DIRECTIVE
"font-src", // FONT_SRC_DIRECTIVE
"connect-src", // CONNECT_SRC_DIRECTIVE
"report-uri", // REPORT_URI_DIRECTIVE
"frame-ancestors", // FRAME_ANCESTORS_DIRECTIVE
"reflected-xss", // REFLECTED_XSS_DIRECTIVE
"base-uri", // BASE_URI_DIRECTIVE
"form-action", // FORM_ACTION_DIRECTIVE
"referrer", // REFERRER_DIRECTIVE
"manifest-src" // MANIFEST_SRC_DIRECTIVE
"-error-", // NO_DIRECTIVE
"default-src", // DEFAULT_SRC_DIRECTIVE
"script-src", // SCRIPT_SRC_DIRECTIVE
"object-src", // OBJECT_SRC_DIRECTIVE
"style-src", // STYLE_SRC_DIRECTIVE
"img-src", // IMG_SRC_DIRECTIVE
"media-src", // MEDIA_SRC_DIRECTIVE
"frame-src", // FRAME_SRC_DIRECTIVE
"font-src", // FONT_SRC_DIRECTIVE
"connect-src", // CONNECT_SRC_DIRECTIVE
"report-uri", // REPORT_URI_DIRECTIVE
"frame-ancestors", // FRAME_ANCESTORS_DIRECTIVE
"reflected-xss", // REFLECTED_XSS_DIRECTIVE
"base-uri", // BASE_URI_DIRECTIVE
"form-action", // FORM_ACTION_DIRECTIVE
"referrer", // REFERRER_DIRECTIVE
"manifest-src", // MANIFEST_SRC_DIRECTIVE
"upgrade-insecure-requests" // UPGRADE_IF_INSECURE_DIRECTIVE
};
inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
@ -182,7 +183,8 @@ class nsCSPBaseSrc {
nsCSPBaseSrc();
virtual ~nsCSPBaseSrc();
virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const;
virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
virtual void toString(nsAString& outStr) const = 0;
};
@ -194,7 +196,8 @@ class nsCSPSchemeSrc : public nsCSPBaseSrc {
explicit nsCSPSchemeSrc(const nsAString& aScheme);
virtual ~nsCSPSchemeSrc();
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const;
void toString(nsAString& outStr) const;
private:
@ -208,10 +211,11 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
explicit nsCSPHostSrc(const nsAString& aHost);
virtual ~nsCSPHostSrc();
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const;
void toString(nsAString& outStr) const;
void setScheme(const nsAString& aScheme, bool aAllowHttps = false);
void setScheme(const nsAString& aScheme);
void setPort(const nsAString& aPort);
void appendPath(const nsAString &aPath);
@ -220,7 +224,6 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
nsString mHost;
nsString mPort;
nsString mPath;
bool mAllowHttps;
};
/* =============== nsCSPKeywordSrc ============ */
@ -247,7 +250,8 @@ class nsCSPNonceSrc : public nsCSPBaseSrc {
explicit nsCSPNonceSrc(const nsAString& aNonce);
virtual ~nsCSPNonceSrc();
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const;
bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
void toString(nsAString& outStr) const;
@ -287,17 +291,16 @@ class nsCSPReportURI : public nsCSPBaseSrc {
class nsCSPDirective {
public:
nsCSPDirective();
explicit nsCSPDirective(CSPDirective aDirective);
virtual ~nsCSPDirective();
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
bool permits(nsIURI* aUri) const;
bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
void toString(nsAString& outStr) const;
virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const;
virtual bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
virtual void toString(nsAString& outStr) const;
void toDomCSPStruct(mozilla::dom::CSP& outCSP) const;
inline void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
virtual void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
{ mSrcs = aSrcs; }
bool restrictsContentType(nsContentPolicyType aContentType) const;
@ -315,6 +318,58 @@ class nsCSPDirective {
nsTArray<nsCSPBaseSrc*> mSrcs;
};
/* =============== nsUpgradeInsecureDirective === */
/*
* Upgrading insecure requests includes the following actors:
* (1) CSP:
* The CSP implementation whitelists the http-request
* in case the policy is executed in enforcement mode.
* The CSP implementation however does not allow http
* requests to succeed if executed in report-only mode.
* In such a case the CSP implementation reports the
* error back to the page.
*
* (2) MixedContent:
* The evalution of MixedContent whitelists all http
* requests with the promise that the http requests
* gets upgraded to https before any data is fetched
* from the network.
*
* (3) CORS:
* Does not consider the http request to be of a
* different origin in case the scheme is the only
* difference in otherwise matching URIs.
*
* (4) nsHttpChannel:
* Before connecting, the channel gets redirected
* to use https.
*
* (5) WebSocketChannel:
* Similar to the httpChannel, the websocketchannel
* gets upgraded from ws to wss.
*/
class nsUpgradeInsecureDirective : public nsCSPDirective {
public:
explicit nsUpgradeInsecureDirective(CSPDirective aDirective);
~nsUpgradeInsecureDirective();
bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
bool aReportOnly, bool aUpgradeInsecure) const
{ return false; }
bool permits(nsIURI* aUri) const
{ return false; }
bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const
{ return false; }
void toString(nsAString& outStr) const;
void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
{ MOZ_ASSERT(false, "upgrade-insecure-requests does not hold any srcs"); }
};
/* =============== nsCSPPolicy ================== */
class nsCSPPolicy {
@ -342,6 +397,12 @@ class nsCSPPolicy {
inline void addDirective(nsCSPDirective* aDir)
{ mDirectives.AppendElement(aDir); }
inline void addUpgradeInsecDir(nsUpgradeInsecureDirective* aDir)
{
mUpgradeInsecDir = aDir;
addDirective(aDir);
}
bool hasDirective(CSPDirective aDir) const;
inline void setReportOnlyFlag(bool aFlag)
@ -367,9 +428,10 @@ class nsCSPPolicy {
{ return mDirectives.Length(); }
private:
nsTArray<nsCSPDirective*> mDirectives;
bool mReportOnly;
nsString mReferrerPolicy;
nsUpgradeInsecureDirective* mUpgradeInsecDir;
nsTArray<nsCSPDirective*> mDirectives;
bool mReportOnly;
nsString mReferrerPolicy;
};
#endif /* nsCSPUtils_h___ */