mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1037335 - Implement security policy violation event. r=ckerschb,smaug
MozReview-Commit-ID: 4BYThUXduI4 --HG-- extra : rebase_source : 5d4a34c5e6bb7fd3774fafb1de72e761bce4591f
This commit is contained in:
parent
748dad0399
commit
8dd7eb1b95
@ -6,13 +6,10 @@
|
||||
#include "nsIContentPolicy.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIChannel;
|
||||
interface nsIDocShell;
|
||||
interface nsIDOMDocument;
|
||||
interface nsIEventTarget;
|
||||
interface nsIPrincipal;
|
||||
interface nsIScriptElement;
|
||||
interface nsIURI;
|
||||
|
||||
/**
|
||||
* nsIContentSecurityPolicy
|
||||
|
@ -843,37 +843,29 @@ StripURIForReporting(nsIURI* aURI,
|
||||
aURI->GetSpecIgnoringRef(outStrippedURI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends CSP violation reports to all sources listed under report-uri.
|
||||
*
|
||||
* @param aBlockedContentSource
|
||||
* Either a CSP Source (like 'self', as string) or nsIURI: the source
|
||||
* of the violation.
|
||||
* @param aOriginalUri
|
||||
* The original URI if the blocked content is a redirect, else null
|
||||
* @param aViolatedDirective
|
||||
* the directive that was violated (string).
|
||||
* @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)
|
||||
*/
|
||||
nsresult
|
||||
nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
nsIURI* aOriginalURI,
|
||||
nsAString& aViolatedDirective,
|
||||
uint32_t aViolatedPolicyIndex,
|
||||
nsAString& aSourceFile,
|
||||
nsAString& aScriptSample,
|
||||
uint32_t aLineNum)
|
||||
nsCSPContext::GatherSecurityPolicyViolationEventData(
|
||||
nsISupports* aBlockedContentSource,
|
||||
nsIURI* aOriginalURI,
|
||||
nsAString& aViolatedDirective,
|
||||
uint32_t aViolatedPolicyIndex,
|
||||
nsAString& aSourceFile,
|
||||
nsAString& aScriptSample,
|
||||
uint32_t aLineNum,
|
||||
mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit)
|
||||
{
|
||||
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
|
||||
|
||||
dom::CSPReport report;
|
||||
nsresult rv;
|
||||
|
||||
// document-uri
|
||||
nsAutoCString reportDocumentURI;
|
||||
StripURIForReporting(mSelfURI, mSelfURI, reportDocumentURI);
|
||||
aViolationEventInit.mDocumentURI = NS_ConvertUTF8toUTF16(reportDocumentURI);
|
||||
|
||||
// referrer
|
||||
aViolationEventInit.mReferrer = mReferrer;
|
||||
|
||||
// blocked-uri
|
||||
if (aBlockedContentSource) {
|
||||
nsAutoCString reportBlockedURI;
|
||||
@ -892,27 +884,20 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
// ancestor is cross-origin.
|
||||
NS_WARNING("No blocked URI (null aBlockedContentSource) for CSP violation report.");
|
||||
}
|
||||
report.mCsp_report.mBlocked_uri = NS_ConvertUTF8toUTF16(reportBlockedURI);
|
||||
aViolationEventInit.mBlockedURI = NS_ConvertUTF8toUTF16(reportBlockedURI);
|
||||
}
|
||||
|
||||
// document-uri
|
||||
nsAutoCString reportDocumentURI;
|
||||
StripURIForReporting(mSelfURI, mSelfURI, reportDocumentURI);
|
||||
report.mCsp_report.mDocument_uri = NS_ConvertUTF8toUTF16(reportDocumentURI);
|
||||
// violated-directive
|
||||
aViolationEventInit.mViolatedDirective = aViolatedDirective;
|
||||
|
||||
// effective-directive
|
||||
aViolationEventInit.mEffectiveDirective = aViolatedDirective;
|
||||
|
||||
// original-policy
|
||||
nsAutoString originalPolicy;
|
||||
rv = this->GetPolicyString(aViolatedPolicyIndex, originalPolicy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
report.mCsp_report.mOriginal_policy = originalPolicy;
|
||||
|
||||
// referrer
|
||||
if (!mReferrer.IsEmpty()) {
|
||||
report.mCsp_report.mReferrer = mReferrer;
|
||||
}
|
||||
|
||||
// violated-directive
|
||||
report.mCsp_report.mViolated_directive = aViolatedDirective;
|
||||
aViolationEventInit.mOriginalPolicy = originalPolicy;
|
||||
|
||||
// source-file
|
||||
if (!aSourceFile.IsEmpty()) {
|
||||
@ -924,20 +909,87 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
sourceURI->GetSpecIgnoringRef(spec);
|
||||
aSourceFile = NS_ConvertUTF8toUTF16(spec);
|
||||
}
|
||||
aViolationEventInit.mSourceFile = aSourceFile;
|
||||
}
|
||||
|
||||
// sample
|
||||
aViolationEventInit.mSample = aScriptSample;
|
||||
|
||||
// disposition
|
||||
aViolationEventInit.mDisposition = mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag()
|
||||
? mozilla::dom::SecurityPolicyViolationEventDisposition::Report
|
||||
: mozilla::dom::SecurityPolicyViolationEventDisposition::Enforce;
|
||||
|
||||
// status-code
|
||||
uint16_t statusCode = 0;
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
|
||||
if (doc) {
|
||||
nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(doc->GetChannel());
|
||||
if (channel) {
|
||||
uint32_t responseStatus = 0;
|
||||
nsresult rv = channel->GetResponseStatus(&responseStatus);
|
||||
if (NS_SUCCEEDED(rv) && (responseStatus <= UINT16_MAX)) {
|
||||
statusCode = static_cast<uint16_t>(responseStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
aViolationEventInit.mStatusCode = statusCode;
|
||||
|
||||
// line-number
|
||||
aViolationEventInit.mLineNumber = aLineNum;
|
||||
|
||||
// column-number
|
||||
// TODO: Set correct column number.
|
||||
aViolationEventInit.mColumnNumber = 0;
|
||||
|
||||
aViolationEventInit.mBubbles = true;
|
||||
aViolationEventInit.mComposed = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSPContext::SendReports(
|
||||
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit,
|
||||
uint32_t aViolatedPolicyIndex)
|
||||
{
|
||||
NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
|
||||
|
||||
dom::CSPReport report;
|
||||
|
||||
// blocked-uri
|
||||
report.mCsp_report.mBlocked_uri = aViolationEventInit.mBlockedURI;
|
||||
|
||||
// document-uri
|
||||
report.mCsp_report.mDocument_uri = aViolationEventInit.mDocumentURI;
|
||||
|
||||
// original-policy
|
||||
report.mCsp_report.mOriginal_policy = aViolationEventInit.mOriginalPolicy;
|
||||
|
||||
// referrer
|
||||
report.mCsp_report.mReferrer = aViolationEventInit.mReferrer;
|
||||
|
||||
// violated-directive
|
||||
report.mCsp_report.mViolated_directive = aViolationEventInit.mViolatedDirective;
|
||||
|
||||
// source-file
|
||||
if (!aViolationEventInit.mSourceFile.IsEmpty()) {
|
||||
report.mCsp_report.mSource_file.Construct();
|
||||
report.mCsp_report.mSource_file.Value() = aSourceFile;
|
||||
report.mCsp_report.mSource_file.Value() = aViolationEventInit.mSourceFile;
|
||||
}
|
||||
|
||||
// script-sample
|
||||
if (!aScriptSample.IsEmpty()) {
|
||||
if (!aViolationEventInit.mSample.IsEmpty()) {
|
||||
report.mCsp_report.mScript_sample.Construct();
|
||||
report.mCsp_report.mScript_sample.Value() = aScriptSample;
|
||||
report.mCsp_report.mScript_sample.Value() = aViolationEventInit.mSample;
|
||||
}
|
||||
|
||||
// line-number
|
||||
if (aLineNum != 0) {
|
||||
if (aViolationEventInit.mLineNumber != 0) {
|
||||
report.mCsp_report.mLine_number.Construct();
|
||||
report.mCsp_report.mLine_number.Value() = aLineNum;
|
||||
report.mCsp_report.mLine_number.Value() = aViolationEventInit.mLineNumber;
|
||||
}
|
||||
|
||||
nsString csp_report;
|
||||
@ -950,11 +1002,11 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
nsTArray<nsString> reportURIs;
|
||||
mPolicies[aViolatedPolicyIndex]->getReportURIs(reportURIs);
|
||||
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
|
||||
nsCOMPtr<nsIURI> reportURI;
|
||||
nsCOMPtr<nsIChannel> reportChannel;
|
||||
|
||||
nsresult rv;
|
||||
for (uint32_t r = 0; r < reportURIs.Length(); r++) {
|
||||
nsAutoCString reportURICstring = NS_ConvertUTF16toUTF8(reportURIs[r]);
|
||||
// try to create a new uri from every report-uri string
|
||||
@ -964,7 +1016,8 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
CSPCONTEXTLOG(("Could not create nsIURI for report URI %s",
|
||||
reportURICstring.get()));
|
||||
logToConsole("triedToSendReport", params, ArrayLength(params),
|
||||
aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
|
||||
aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
|
||||
aViolationEventInit.mLineNumber, 0, nsIScriptError::errorFlag);
|
||||
continue; // don't return yet, there may be more URIs
|
||||
}
|
||||
|
||||
@ -1005,7 +1058,8 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
if (!isHttpScheme) {
|
||||
const char16_t* params[] = { reportURIs[r].get() };
|
||||
logToConsole("reportURInotHttpsOrHttp2", params, ArrayLength(params),
|
||||
aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
|
||||
aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
|
||||
aViolationEventInit.mLineNumber, 0, nsIScriptError::errorFlag);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1070,7 +1124,8 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
const char16_t* params[] = { reportURIs[r].get() };
|
||||
CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", NS_ConvertUTF16toUTF8(params[0]).get()));
|
||||
logToConsole("triedToSendReport", params, ArrayLength(params),
|
||||
aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
|
||||
aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
|
||||
aViolationEventInit.mLineNumber, 0, nsIScriptError::errorFlag);
|
||||
} else {
|
||||
CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get()));
|
||||
}
|
||||
@ -1078,6 +1133,26 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSPContext::FireViolationEvent(
|
||||
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
|
||||
if (!doc) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<mozilla::dom::Event> event =
|
||||
mozilla::dom::SecurityPolicyViolationEvent::Constructor(
|
||||
doc,
|
||||
NS_LITERAL_STRING("securitypolicyviolation"),
|
||||
aViolationEventInit);
|
||||
event->SetTrusted(true);
|
||||
|
||||
bool rv;
|
||||
return doc->DispatchEvent(event, &rv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatched from the main thread to send reports for one CSP violation.
|
||||
*/
|
||||
@ -1124,6 +1199,14 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// 0) prepare violation data
|
||||
mozilla::dom::SecurityPolicyViolationEventInit init;
|
||||
mCSPContext->GatherSecurityPolicyViolationEventData(
|
||||
mBlockedContentSource, mOriginalURI,
|
||||
mViolatedDirective, mViolatedPolicyIndex,
|
||||
mSourceFile, mScriptSample, mLineNum,
|
||||
init);
|
||||
|
||||
// 1) notify observers
|
||||
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
||||
NS_ASSERTION(observerService, "needs observer service");
|
||||
@ -1133,9 +1216,7 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// 2) send reports for the policy that was violated
|
||||
mCSPContext->SendReports(mBlockedContentSource, mOriginalURI,
|
||||
mViolatedDirective, mViolatedPolicyIndex,
|
||||
mSourceFile, mScriptSample, mLineNum);
|
||||
mCSPContext->SendReports(init, mViolatedPolicyIndex);
|
||||
|
||||
// 3) log to console (one per policy violation)
|
||||
// mBlockedContentSource could be a URI or a string.
|
||||
@ -1168,6 +1249,10 @@ class CSPReportSenderRunnable final : public Runnable
|
||||
params, ArrayLength(params), mSourceFile, mScriptSample,
|
||||
mLineNum, 0, nsIScriptError::errorFlag);
|
||||
}
|
||||
|
||||
// 4) fire violation event
|
||||
mCSPContext->FireViolationEvent(init);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define nsCSPContext_h___
|
||||
|
||||
#include "mozilla/dom/nsCSPUtils.h"
|
||||
#include "mozilla/dom/SecurityPolicyViolationEvent.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
@ -58,13 +59,43 @@ class nsCSPContext : public nsIContentSecurityPolicy
|
||||
uint32_t aColumnNumber,
|
||||
uint32_t aSeverityFlag);
|
||||
|
||||
nsresult SendReports(nsISupports* aBlockedContentSource,
|
||||
nsIURI* aOriginalURI,
|
||||
nsAString& aViolatedDirective,
|
||||
uint32_t aViolatedPolicyIndex,
|
||||
nsAString& aSourceFile,
|
||||
nsAString& aScriptSample,
|
||||
uint32_t aLineNum);
|
||||
|
||||
|
||||
/**
|
||||
* Construct SecurityPolicyViolationEventInit structure.
|
||||
*
|
||||
* @param aBlockedContentSource
|
||||
* Either a CSP Source (like 'self', as string) or nsIURI: the source
|
||||
* of the violation.
|
||||
* @param aOriginalUri
|
||||
* The original URI if the blocked content is a redirect, else null
|
||||
* @param aViolatedDirective
|
||||
* the directive that was violated (string).
|
||||
* @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)
|
||||
* @param aViolationEventInit
|
||||
* The output
|
||||
*/
|
||||
nsresult GatherSecurityPolicyViolationEventData(
|
||||
nsISupports* aBlockedContentSource,
|
||||
nsIURI* aOriginalURI,
|
||||
nsAString& aViolatedDirective,
|
||||
uint32_t aViolatedPolicyIndex,
|
||||
nsAString& aSourceFile,
|
||||
nsAString& aScriptSample,
|
||||
uint32_t aLineNum,
|
||||
mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit);
|
||||
|
||||
nsresult SendReports(
|
||||
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit,
|
||||
uint32_t aViolatedPolicyIndex);
|
||||
|
||||
nsresult FireViolationEvent(
|
||||
const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit);
|
||||
|
||||
nsresult AsyncReportViolation(nsISupports* aBlockedContentSource,
|
||||
nsIURI* aOriginalURI,
|
||||
|
41
dom/webidl/SecurityPolicyViolationEvent.webidl
Normal file
41
dom/webidl/SecurityPolicyViolationEvent.webidl
Normal file
@ -0,0 +1,41 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
enum SecurityPolicyViolationEventDisposition
|
||||
{
|
||||
"enforce", "report"
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional SecurityPolicyViolationEventInit eventInitDict)]
|
||||
interface SecurityPolicyViolationEvent : Event
|
||||
{
|
||||
readonly attribute DOMString documentURI;
|
||||
readonly attribute DOMString referrer;
|
||||
readonly attribute DOMString blockedURI;
|
||||
readonly attribute DOMString violatedDirective;
|
||||
readonly attribute DOMString effectiveDirective;
|
||||
readonly attribute DOMString originalPolicy;
|
||||
readonly attribute DOMString sourceFile;
|
||||
readonly attribute DOMString sample;
|
||||
readonly attribute SecurityPolicyViolationEventDisposition disposition;
|
||||
readonly attribute unsigned short statusCode;
|
||||
readonly attribute long lineNumber;
|
||||
readonly attribute long columnNumber;
|
||||
};
|
||||
|
||||
dictionary SecurityPolicyViolationEventInit : EventInit
|
||||
{
|
||||
DOMString documentURI = "";
|
||||
DOMString referrer = "";
|
||||
DOMString blockedURI = "";
|
||||
DOMString violatedDirective = "";
|
||||
DOMString effectiveDirective = "";
|
||||
DOMString originalPolicy = "";
|
||||
DOMString sourceFile = "";
|
||||
DOMString sample = "";
|
||||
SecurityPolicyViolationEventDisposition disposition = "report";
|
||||
unsigned short statusCode = 0;
|
||||
long lineNumber = 0;
|
||||
long columnNumber = 0;
|
||||
};
|
@ -1089,6 +1089,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
|
||||
'ProgressEvent.webidl',
|
||||
'PromiseRejectionEvent.webidl',
|
||||
'ScrollViewChangeEvent.webidl',
|
||||
'SecurityPolicyViolationEvent.webidl',
|
||||
'StyleRuleChangeEvent.webidl',
|
||||
'StyleSheetApplicableStateChangeEvent.webidl',
|
||||
'StyleSheetChangeEvent.webidl',
|
||||
|
Loading…
Reference in New Issue
Block a user