зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1473218 - Implement report-sample support for CSP directives, r=ckerschb
This commit is contained in:
Родитель
25a1215bb8
Коммит
9042bfbc94
|
@ -563,10 +563,13 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
|||
*outAllowsInline = false;
|
||||
}
|
||||
nsAutoString violatedDirective;
|
||||
mPolicies[i]->getDirectiveStringForContentType(aContentType, violatedDirective);
|
||||
bool reportSample = false;
|
||||
mPolicies[i]->getDirectiveStringAndReportSampleForContentType(aContentType,
|
||||
violatedDirective,
|
||||
&reportSample);
|
||||
reportInlineViolation(aContentType,
|
||||
aNonce,
|
||||
content,
|
||||
reportSample ? content : EmptyString(),
|
||||
violatedDirective,
|
||||
i,
|
||||
aLineNumber,
|
||||
|
@ -613,13 +616,16 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
|||
keyword, nonceOrHash, false)) \
|
||||
{ \
|
||||
nsAutoString violatedDirective; \
|
||||
mPolicies[p]->getDirectiveStringForContentType( \
|
||||
bool reportSample = false; \
|
||||
mPolicies[p]->getDirectiveStringAndReportSampleForContentType( \
|
||||
nsIContentPolicy::TYPE_ ## contentPolicyType, \
|
||||
violatedDirective); \
|
||||
violatedDirective, &reportSample); \
|
||||
this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
|
||||
NS_LITERAL_STRING(observerTopic), \
|
||||
aSourceFile, aScriptSample, aLineNum, \
|
||||
aColumnNum); \
|
||||
aSourceFile, \
|
||||
reportSample \
|
||||
? aScriptSample : EmptyString(), \
|
||||
aLineNum, aColumnNum); \
|
||||
} \
|
||||
PR_END_MACRO; \
|
||||
break
|
||||
|
@ -1265,7 +1271,7 @@ class CSPReportSenderRunnable final : public Runnable
|
|||
rv = blockedURI->SchemeIs("data", &isData);
|
||||
if (NS_SUCCEEDED(rv) && isData) {
|
||||
blockedDataStr.Truncate(40);
|
||||
blockedDataStr.AppendASCII("...");
|
||||
blockedDataStr.AppendASCII("…");
|
||||
}
|
||||
}
|
||||
} else if (blockedString) {
|
||||
|
|
|
@ -482,6 +482,10 @@ nsCSPParser::keywordSource()
|
|||
return CSP_CreateHostSrcFromSelfURI(mSelfURI);
|
||||
}
|
||||
|
||||
if (CSP_IsKeyword(mCurToken, CSP_REPORT_SAMPLE)) {
|
||||
return new nsCSPKeywordSrc(CSP_UTF16KeywordToEnum(mCurToken));
|
||||
}
|
||||
|
||||
if (CSP_IsKeyword(mCurToken, CSP_STRICT_DYNAMIC)) {
|
||||
// make sure strict dynamic is enabled
|
||||
if (!sStrictDynamicEnabled) {
|
||||
|
@ -800,9 +804,10 @@ nsCSPParser::sourceList(nsTArray<nsCSPBaseSrc*>& outSrcs)
|
|||
// Check if the directive contains a 'none'
|
||||
if (isNone) {
|
||||
// If the directive contains no other srcs, then we set the 'none'
|
||||
if (outSrcs.Length() == 0) {
|
||||
if (outSrcs.IsEmpty() ||
|
||||
(outSrcs.Length() == 1 && outSrcs[0]->isReportSample())) {
|
||||
nsCSPKeywordSrc *keyword = new nsCSPKeywordSrc(CSP_NONE);
|
||||
outSrcs.AppendElement(keyword);
|
||||
outSrcs.InsertElementAt(0, keyword);
|
||||
}
|
||||
// Otherwise, we ignore 'none' and report a warning
|
||||
else {
|
||||
|
@ -1150,9 +1155,10 @@ nsCSPParser::directive()
|
|||
|
||||
// If we can not parse any srcs; we let the source expression be the empty set ('none')
|
||||
// see, http://www.w3.org/TR/CSP11/#source-list-parsing
|
||||
if (srcs.Length() == 0) {
|
||||
if (srcs.IsEmpty() ||
|
||||
(srcs.Length() == 1 && srcs[0]->isReportSample())) {
|
||||
nsCSPKeywordSrc *keyword = new nsCSPKeywordSrc(CSP_NONE);
|
||||
srcs.AppendElement(keyword);
|
||||
srcs.InsertElementAt(0, keyword);
|
||||
}
|
||||
|
||||
// If policy contains 'strict-dynamic' invalidate all srcs within script-src.
|
||||
|
|
|
@ -1264,6 +1264,18 @@ nsCSPDirective::getDirName(nsAString& outStr) const
|
|||
outStr.AppendASCII(CSP_CSPDirectiveToString(mDirective));
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSPDirective::hasReportSampleKeyword() const
|
||||
{
|
||||
for (nsCSPBaseSrc* src : mSrcs) {
|
||||
if (src->isReportSample()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* =============== nsCSPChildSrcDirective ============= */
|
||||
|
||||
nsCSPChildSrcDirective::nsCSPChildSrcDirective(CSPDirective aDirective)
|
||||
|
@ -1614,13 +1626,18 @@ nsCSPPolicy::hasDirective(CSPDirective aDir) const
|
|||
* for the ::permits() function family.
|
||||
*/
|
||||
void
|
||||
nsCSPPolicy::getDirectiveStringForContentType(nsContentPolicyType aContentType,
|
||||
nsAString& outDirective) const
|
||||
nsCSPPolicy::getDirectiveStringAndReportSampleForContentType(nsContentPolicyType aContentType,
|
||||
nsAString& outDirective,
|
||||
bool* aReportSample) const
|
||||
{
|
||||
MOZ_ASSERT(aReportSample);
|
||||
*aReportSample = false;
|
||||
|
||||
nsCSPDirective* defaultDir = nullptr;
|
||||
for (uint32_t i = 0; i < mDirectives.Length(); i++) {
|
||||
if (mDirectives[i]->restrictsContentType(aContentType)) {
|
||||
mDirectives[i]->getDirName(outDirective);
|
||||
*aReportSample = mDirectives[i]->hasReportSampleKeyword();
|
||||
return;
|
||||
}
|
||||
if (mDirectives[i]->isDefaultDirective()) {
|
||||
|
@ -1631,6 +1648,7 @@ nsCSPPolicy::getDirectiveStringForContentType(nsContentPolicyType aContentType,
|
|||
// the contentType must be restricted by the default directive
|
||||
if (defaultDir) {
|
||||
defaultDir->getDirName(outDirective);
|
||||
*aReportSample = defaultDir->hasReportSampleKeyword();
|
||||
return;
|
||||
}
|
||||
NS_ASSERTION(false, "Can not query directive string for contentType!");
|
||||
|
|
|
@ -126,6 +126,7 @@ inline CSPDirective CSP_StringToCSPDirective(const nsAString& aDir)
|
|||
macro(CSP_NONE, "'none'") \
|
||||
macro(CSP_NONCE, "'nonce-") \
|
||||
macro(CSP_REQUIRE_SRI_FOR, "require-sri-for") \
|
||||
macro(CSP_REPORT_SAMPLE, "'report-sample'") \
|
||||
macro(CSP_STRICT_DYNAMIC, "'strict-dynamic'")
|
||||
|
||||
enum CSPKeyword {
|
||||
|
@ -238,6 +239,9 @@ class nsCSPBaseSrc {
|
|||
virtual void invalidate() const
|
||||
{ mInvalidated = true; }
|
||||
|
||||
virtual bool isReportSample() const
|
||||
{ return false; }
|
||||
|
||||
protected:
|
||||
// invalidate srcs if 'script-dynamic' is present or also invalidate
|
||||
// unsafe-inline' if nonce- or hash-source specified
|
||||
|
@ -336,6 +340,8 @@ class nsCSPKeywordSrc : public nsCSPBaseSrc {
|
|||
}
|
||||
}
|
||||
|
||||
bool isReportSample() const override
|
||||
{ return mKeyword == CSP_REPORT_SAMPLE; }
|
||||
private:
|
||||
CSPKeyword mKeyword;
|
||||
};
|
||||
|
@ -475,6 +481,8 @@ class nsCSPDirective {
|
|||
|
||||
virtual void getDirName(nsAString& outStr) const;
|
||||
|
||||
bool hasReportSampleKeyword() const;
|
||||
|
||||
protected:
|
||||
CSPDirective mDirective;
|
||||
nsTArray<nsCSPBaseSrc*> mSrcs;
|
||||
|
@ -678,8 +686,9 @@ class nsCSPPolicy {
|
|||
|
||||
void getReportURIs(nsTArray<nsString> &outReportURIs) const;
|
||||
|
||||
void getDirectiveStringForContentType(nsContentPolicyType aContentType,
|
||||
nsAString& outDirective) const;
|
||||
void getDirectiveStringAndReportSampleForContentType(nsContentPolicyType aContentType,
|
||||
nsAString& outDirective,
|
||||
bool* aReportSample) const;
|
||||
|
||||
void getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const;
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Content-Security-Policy: default-src 'self'; img-src 'none'
|
||||
Content-Security-Policy: default-src 'self' 'report-sample'; img-src 'none' 'report-sample'
|
||||
|
|
|
@ -32,7 +32,7 @@ SpecialPowers.registerConsoleListener(function ConsoleMsgListener(aMsg) {
|
|||
data_uri = "";
|
||||
data_uri = aMsg.message.substr(data_start);
|
||||
// this will either match the elipsis after the URI or the . at the end of the message
|
||||
data_uri = data_uri.substr(0, data_uri.indexOf("."));
|
||||
data_uri = data_uri.substr(0, data_uri.indexOf("…"));
|
||||
if (data_uri == "") {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -29,10 +29,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=548193
|
|||
|
||||
const testfile = "tests/dom/security/test/csp/file_report.html";
|
||||
const reportURI = "http://mochi.test:8888/foo.sjs";
|
||||
const policy = "default-src 'none'; report-uri " + reportURI;
|
||||
const policy = "default-src 'none' 'report-sample'; report-uri " + reportURI;
|
||||
const docUri = "http://mochi.test:8888/tests/dom/security/test/csp/file_testserver.sjs" +
|
||||
"?file=tests/dom/security/test/csp/file_report.html" +
|
||||
"&csp=default-src%20%27none%27%3B%20report-uri%20http%3A//mochi.test%3A8888/foo.sjs";
|
||||
"&csp=default-src%20%27none%27%20%27report-sample%27%3B%20report-uri%20http%3A//mochi.test%3A8888/foo.sjs";
|
||||
|
||||
window.checkResults = function(reportObj) {
|
||||
var cspReport = reportObj["csp-report"];
|
||||
|
@ -52,7 +52,7 @@ window.checkResults = function(reportObj) {
|
|||
|
||||
is(cspReport["violated-directive"], "default-src", "Incorrect violated-directive");
|
||||
|
||||
is(cspReport["original-policy"], "default-src 'none'; report-uri http://mochi.test:8888/foo.sjs",
|
||||
is(cspReport["original-policy"], "default-src 'none' 'report-sample'; report-uri http://mochi.test:8888/foo.sjs",
|
||||
"Incorrect original-policy");
|
||||
|
||||
is(cspReport["source-file"], docUri, "Incorrect source-file");
|
||||
|
|
|
@ -70,7 +70,7 @@ function makeTest(id, expectedJSON, useReportOnlyPolicy, callback) {
|
|||
// set up a new CSP instance for each test.
|
||||
var csp = Cc["@mozilla.org/cspcontext;1"]
|
||||
.createInstance(Ci.nsIContentSecurityPolicy);
|
||||
var policy = "default-src 'none'; " +
|
||||
var policy = "default-src 'none' 'report-sample'; " +
|
||||
"report-uri " + REPORT_SERVER_URI +
|
||||
":" + REPORT_SERVER_PORT +
|
||||
"/test" + id;
|
||||
|
|
|
@ -1071,7 +1071,7 @@ add_task(async function test_contentscript_csp() {
|
|||
let chaosMode = parseInt(env.get("MOZ_CHAOSMODE"), 16);
|
||||
let checkCSPReports = !(chaosMode === 0 || chaosMode & 0x02);
|
||||
|
||||
gContentSecurityPolicy = `default-src 'none'; script-src 'nonce-deadbeef' 'unsafe-eval'; report-uri ${CSP_REPORT_PATH};`;
|
||||
gContentSecurityPolicy = `default-src 'none' 'report-sample'; script-src 'nonce-deadbeef' 'unsafe-eval' 'report-sample'; report-uri ${CSP_REPORT_PATH};`;
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(EXTENSION_DATA);
|
||||
await extension.startup();
|
||||
|
|
Загрузка…
Ссылка в новой задаче