mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 515437 CSP connection code, r=jst,dveditz sr=jst
This commit is contained in:
parent
553a8c9c5a
commit
f2278605c1
@ -47,11 +47,12 @@ struct JSPrincipals;
|
||||
%}
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIContentSecurityPolicy;
|
||||
|
||||
[ptr] native JSContext(JSContext);
|
||||
[ptr] native JSPrincipals(JSPrincipals);
|
||||
|
||||
[scriptable, uuid(b8268b9a-2403-44ed-81e3-614075c92034)]
|
||||
[scriptable, uuid(799ab95c-0038-4e0f-b705-74c21f185bb5)]
|
||||
interface nsIPrincipal : nsISerializable
|
||||
{
|
||||
/**
|
||||
@ -241,4 +242,9 @@ interface nsIPrincipal : nsISerializable
|
||||
* one, this will return null. Getting this attribute never throws.
|
||||
*/
|
||||
readonly attribute nsISupports certificate;
|
||||
|
||||
/**
|
||||
* A Content Security Policy associated with this principal.
|
||||
*/
|
||||
[noscript] attribute nsIContentSecurityPolicy csp;
|
||||
};
|
||||
|
@ -138,6 +138,7 @@ protected:
|
||||
|
||||
DomainPolicy* mSecurityPolicy;
|
||||
|
||||
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
|
||||
nsCOMPtr<nsIURI> mCodebase;
|
||||
nsCOMPtr<nsIURI> mDomain;
|
||||
PRPackedBool mTrusted;
|
||||
|
@ -251,6 +251,21 @@ nsNullPrincipal::GetURI(nsIURI** aURI)
|
||||
return NS_EnsureSafeToReturn(mURI, aURI);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
|
||||
{
|
||||
// CSP on a null principal makes no sense
|
||||
*aCsp = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
|
||||
{
|
||||
// CSP on a null principal makes no sense
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::GetDomain(nsIURI** aDomain)
|
||||
{
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
|
||||
#include "nsPrincipal.h"
|
||||
|
||||
@ -774,6 +775,25 @@ nsPrincipal::GetCertificate(nsISupports** aCertificate)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
|
||||
{
|
||||
NS_IF_ADDREF(*aCsp = mCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
|
||||
{
|
||||
// If CSP was already set, it should not be destroyed! Instead, it should
|
||||
// get set anew when a new principal is created.
|
||||
if (mCSP)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
mCSP = aCsp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrincipal::GetHashValue(PRUint32* aValue)
|
||||
{
|
||||
|
@ -223,6 +223,20 @@ nsSystemPrincipal::GetHasCertificate(PRBool* aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
|
||||
{
|
||||
*aCsp = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
|
||||
{
|
||||
// CSP on a null principal makes no sense
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::GetDomain(nsIURI** aDomain)
|
||||
{
|
||||
|
@ -79,6 +79,7 @@ CPPSRCS = \
|
||||
nsContentUtils.cpp \
|
||||
nsCopySupport.cpp \
|
||||
nsCrossSiteListenerProxy.cpp \
|
||||
nsCSPService.cpp \
|
||||
nsDataDocumentContentPolicy.cpp \
|
||||
nsDOMAttribute.cpp \
|
||||
nsDOMAttributeMap.cpp \
|
||||
|
198
content/base/src/nsCSPService.cpp
Normal file
198
content/base/src/nsCSPService.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brandon Sterne <bsterne@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "prlog.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSPService.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
|
||||
/* Keeps track of whether or not CSP is enabled */
|
||||
static PRBool gCSPEnabled = PR_TRUE;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo* gCspPRLog;
|
||||
#endif
|
||||
|
||||
CSPService::CSPService()
|
||||
{
|
||||
nsContentUtils::AddBoolPrefVarCache("security.csp.enable", &gCSPEnabled);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (!gCspPRLog)
|
||||
gCspPRLog = PR_NewLogModule("CSP");
|
||||
#endif
|
||||
}
|
||||
|
||||
CSPService::~CSPService()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(CSPService, nsIContentPolicy)
|
||||
|
||||
/* nsIContentPolicy implementation */
|
||||
NS_IMETHODIMP
|
||||
CSPService::ShouldLoad(PRUint32 aContentType,
|
||||
nsIURI *aContentLocation,
|
||||
nsIURI *aRequestOrigin,
|
||||
nsISupports *aRequestContext,
|
||||
const nsACString &aMimeTypeGuess,
|
||||
nsISupports *aExtra,
|
||||
PRInt16 *aDecision)
|
||||
{
|
||||
if (!aContentLocation)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
{
|
||||
nsCAutoString location;
|
||||
aContentLocation->GetSpec(location);
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSPService::ShouldLoad called for %s", location.get()));
|
||||
}
|
||||
#endif
|
||||
// default decision, CSP can revise it if there's a policy to enforce
|
||||
*aDecision = nsIContentPolicy::ACCEPT;
|
||||
|
||||
// No need to continue processing if CSP is disabled
|
||||
if (!gCSPEnabled)
|
||||
return NS_OK;
|
||||
|
||||
// find the nsDocument that initiated this request and see if it has a
|
||||
// CSP policy object
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINode> node(do_QueryInterface(aRequestContext));
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
if (node) {
|
||||
principal = node->NodePrincipal();
|
||||
principal->GetCsp(getter_AddRefs(csp));
|
||||
|
||||
if (csp) {
|
||||
#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
|
||||
csp->ShouldLoad(aContentType,
|
||||
aContentLocation,
|
||||
aRequestOrigin,
|
||||
aRequestContext,
|
||||
aMimeTypeGuess,
|
||||
aExtra,
|
||||
aDecision);
|
||||
}
|
||||
}
|
||||
#ifdef PR_LOGGING
|
||||
else {
|
||||
nsCAutoString uriSpec;
|
||||
aContentLocation->GetSpec(uriSpec);
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("COULD NOT get nsINode for location: %s", uriSpec.get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CSPService::ShouldProcess(PRUint32 aContentType,
|
||||
nsIURI *aContentLocation,
|
||||
nsIURI *aRequestOrigin,
|
||||
nsISupports *aRequestContext,
|
||||
const nsACString &aMimeTypeGuess,
|
||||
nsISupports *aExtra,
|
||||
PRInt16 *aDecision)
|
||||
{
|
||||
if (!aContentLocation)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// default decision is to accept the item
|
||||
*aDecision = nsIContentPolicy::ACCEPT;
|
||||
|
||||
// No need to continue processing if CSP is disabled
|
||||
if (!gCSPEnabled)
|
||||
return NS_OK;
|
||||
|
||||
// find the nsDocument that initiated this request and see if it has a
|
||||
// CSP policy object
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINode> node(do_QueryInterface(aRequestContext));
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
if (node) {
|
||||
principal = node->NodePrincipal();
|
||||
principal->GetCsp(getter_AddRefs(csp));
|
||||
|
||||
if (csp) {
|
||||
#ifdef PR_LOGGING
|
||||
nsAutoString policy;
|
||||
csp->GetPolicy(policy);
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("shouldProcess - document has policy: %s",
|
||||
NS_ConvertUTF16toUTF8(policy).get()));
|
||||
#endif
|
||||
// obtain the enforcement decision
|
||||
csp->ShouldProcess(aContentType,
|
||||
aContentLocation,
|
||||
aRequestOrigin,
|
||||
aRequestContext,
|
||||
aMimeTypeGuess,
|
||||
aExtra,
|
||||
aDecision);
|
||||
}
|
||||
}
|
||||
#ifdef PR_LOGGING
|
||||
else {
|
||||
nsCAutoString uriSpec;
|
||||
aContentLocation->GetSpec(uriSpec);
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("COULD NOT get nsINode for location: %s", uriSpec.get()));
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
57
content/base/src/nsCSPService.h
Normal file
57
content/base/src/nsCSPService.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brandon Sterne <bsterne@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
|
||||
#define CSPSERVICE_CONTRACTID "@mozilla.org/cspservice;1"
|
||||
#define CSPSERVICE_CID \
|
||||
{ 0x8d2f40b2, 0x4875, 0x4c95, \
|
||||
{ 0x97, 0xd9, 0x3f, 0x7d, 0xca, 0x2c, 0xb4, 0x60 } }
|
||||
class CSPService : public nsIContentPolicy
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPOLICY
|
||||
|
||||
CSPService();
|
||||
virtual ~CSPService();
|
||||
|
||||
private:
|
||||
PRBool mEnabled;
|
||||
};
|
@ -181,6 +181,9 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
|
||||
#include "nsSVGUtils.h"
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
// FOR CSP (autogenerated by xpidl)
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
// so we can get logging even in release builds
|
||||
@ -188,8 +191,12 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
|
||||
#endif
|
||||
#include "prlog.h"
|
||||
|
||||
/* Keeps track of whether or not CSP is enabled */
|
||||
static PRBool gCSPEnabled = PR_TRUE;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo* gDocumentLeakPRLog;
|
||||
static PRLogModuleInfo* gCspPRLog;
|
||||
#endif
|
||||
|
||||
void
|
||||
@ -1495,8 +1502,13 @@ nsDocument::nsDocument(const char* aContentType)
|
||||
if (gDocumentLeakPRLog)
|
||||
PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
|
||||
("DOCUMENT %p created", this));
|
||||
|
||||
if (!gCspPRLog)
|
||||
gCspPRLog = PR_NewLogModule("CSP");
|
||||
#endif
|
||||
|
||||
nsContentUtils::AddBoolPrefVarCache("security.csp.enable", &gCSPEnabled);
|
||||
|
||||
// Start out mLastStyleSheetSet as null, per spec
|
||||
SetDOMStringToNull(mLastStyleSheetSet);
|
||||
}
|
||||
@ -2252,6 +2264,110 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||
|
||||
mChannel = aChannel;
|
||||
|
||||
nsresult rv = InitCSP();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocument::InitCSP()
|
||||
{
|
||||
if (gCSPEnabled) {
|
||||
nsAutoString cspHeaderValue;
|
||||
nsAutoString cspROHeaderValue;
|
||||
|
||||
this->GetHeaderData(nsGkAtoms::headerCSP, cspHeaderValue);
|
||||
this->GetHeaderData(nsGkAtoms::headerCSPReportOnly, cspROHeaderValue);
|
||||
|
||||
PRBool system = PR_FALSE;
|
||||
nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager();
|
||||
|
||||
if (NS_SUCCEEDED(ssm->IsSystemPrincipal(NodePrincipal(), &system)) && system) {
|
||||
// only makes sense to register new CSP if this document is not priviliged
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (cspHeaderValue.IsEmpty() && cspROHeaderValue.IsEmpty()) {
|
||||
// no CSP header present, stop processing
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP header specified for document %p", this));
|
||||
#endif
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
|
||||
mCSP = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to create CSP object: %x", rv));
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Store the request context for violation reports
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
|
||||
mCSP->ScanRequestData(httpChannel);
|
||||
|
||||
// Start parsing the policy
|
||||
nsCOMPtr<nsIURI> chanURI;
|
||||
mChannel->GetURI(getter_AddRefs(chanURI));
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP Loaded"));
|
||||
#endif
|
||||
|
||||
// ReportOnly mode is enabled *only* if there are no regular-strength CSP
|
||||
// headers present. If there are, then we ignore the ReportOnly mode and
|
||||
// toss a warning into the error console, proceeding with enforcing the
|
||||
// regular-strength CSP.
|
||||
if (cspHeaderValue.IsEmpty()) {
|
||||
mCSP->SetReportOnlyMode(true);
|
||||
mCSP->RefinePolicy(cspROHeaderValue, chanURI);
|
||||
#ifdef PR_LOGGING
|
||||
{
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP (report only) refined, policy: \"%s\"",
|
||||
NS_ConvertUTF16toUTF8(cspROHeaderValue).get()));
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//XXX(sstamm): maybe we should post a warning when both read only and regular
|
||||
// CSP headers are present.
|
||||
mCSP->RefinePolicy(cspHeaderValue, chanURI);
|
||||
#ifdef PR_LOGGING
|
||||
{
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP refined, policy: \"%s\"",
|
||||
NS_ConvertUTF16toUTF8(cspHeaderValue).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//Copy into principal
|
||||
nsIPrincipal* principal = GetPrincipal();
|
||||
|
||||
if (principal) {
|
||||
principal->SetCsp(mCSP);
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("Inserted CSP into principal %p", principal));
|
||||
}
|
||||
else {
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("Couldn't copy CSP into absent principal %p", principal));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef PR_LOGGING
|
||||
else { //CSP was not enabled!
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("CSP is disabled, skipping CSP init for document %p", this));
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -6648,6 +6764,8 @@ nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
|
||||
"content-disposition",
|
||||
"refresh",
|
||||
"x-dns-prefetch-control",
|
||||
"x-content-security-policy",
|
||||
"x-content-security-policy-read-only",
|
||||
// add more http headers if you need
|
||||
// XXXbz don't add content-location support without reading bug
|
||||
// 238654 and its dependencies/dups first.
|
||||
|
@ -1213,6 +1213,8 @@ private:
|
||||
void PostUnblockOnloadEvent();
|
||||
void DoUnblockOnload();
|
||||
|
||||
nsresult InitCSP();
|
||||
|
||||
/**
|
||||
* See if aDocument is a child of this. If so, return the frame element in
|
||||
* this document that holds currentDoc (or an ancestor).
|
||||
|
@ -1007,6 +1007,8 @@ GK_ATOM(withParam, "with-param")
|
||||
GK_ATOM(wizard, "wizard")
|
||||
GK_ATOM(wrap, "wrap")
|
||||
GK_ATOM(headerDNSPrefetchControl,"x-dns-prefetch-control")
|
||||
GK_ATOM(headerCSP, "x-content-security-policy")
|
||||
GK_ATOM(headerCSPReportOnly, "x-content-security-policy-report-only")
|
||||
GK_ATOM(xml, "xml")
|
||||
GK_ATOM(xmlns, "xmlns")
|
||||
GK_ATOM(xmp, "xmp")
|
||||
|
@ -333,6 +333,10 @@ _TEST_FILES = test_bug5141.html \
|
||||
test_bug503481b.html \
|
||||
file_bug503481b_inner.html \
|
||||
test_viewport_scroll.html \
|
||||
test_CSP.html \
|
||||
file_CSP.sjs \
|
||||
file_CSP_main.html \
|
||||
file_CSP_main.js \
|
||||
$(NULL)
|
||||
|
||||
# Disabled; see bug 492181
|
||||
|
44
content/base/test/file_CSP.sjs
Normal file
44
content/base/test/file_CSP.sjs
Normal file
@ -0,0 +1,44 @@
|
||||
// SJS file for CSP mochitests
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
var query = {};
|
||||
request.queryString.split('&').forEach(function (val) {
|
||||
var [name, value] = val.split('=');
|
||||
query[name] = unescape(value);
|
||||
});
|
||||
|
||||
var isPreflight = request.method == "OPTIONS";
|
||||
|
||||
|
||||
//avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
if ("main" in query) {
|
||||
var xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Components.interfaces.nsIXMLHttpRequest);
|
||||
//serve the main page with a CSP header!
|
||||
// -- anything served from 'self' (localhost:8888) will be allowed,
|
||||
// -- anything served from other hosts (example.com:80) will be blocked.
|
||||
// -- XHR tests are set up in the file_CSP_main.js file which is sourced.
|
||||
response.setHeader("X-Content-Security-Policy",
|
||||
"allow 'self'",
|
||||
false);
|
||||
xhr.open("GET", "http://localhost:8888/tests/content/base/test/file_CSP_main.html", false);
|
||||
xhr.send(null);
|
||||
if(xhr.status == 200) {
|
||||
response.write(xhr.responseText);
|
||||
}
|
||||
} else {
|
||||
if ("type" in query) {
|
||||
response.setHeader("Content-Type", unescape(query['type']), false);
|
||||
} else {
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
}
|
||||
|
||||
if ("content" in query) {
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(unescape(query['content']));
|
||||
}
|
||||
}
|
||||
}
|
55
content/base/test/file_CSP_main.html
Normal file
55
content/base/test/file_CSP_main.html
Normal file
@ -0,0 +1,55 @@
|
||||
<html>
|
||||
<head>
|
||||
<link rel='stylesheet' type='text/css'
|
||||
href='http://example.org/tests/content/base/test/file_CSP.sjs?testid=style_bad&type=text/css' />
|
||||
<link rel='stylesheet' type='text/css'
|
||||
href='file_CSP.sjs?testid=style_good&type=text/css' />
|
||||
|
||||
|
||||
<style>
|
||||
/* CSS font embedding tests */
|
||||
@font-face {
|
||||
font-family: "arbitrary_good";
|
||||
src: url('file_CSP.sjs?testid=font_good&type=application/octet-stream');
|
||||
}
|
||||
@font-face {
|
||||
font-family: "arbitrary_bad";
|
||||
src: url('http://example.org/tests/content/base/test/file_CSP.sjs?testid=font_bad&type=application/octet-stream');
|
||||
}
|
||||
|
||||
.div_arbitrary_good { font-family: "arbitrary_good"; }
|
||||
.div_arbitrary_bad { font-family: "arbitrary_bad"; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- these should be stopped by CSP. :) -->
|
||||
<img src="http://example.org/tests/content/base/test/file_CSP.sjs?testid=img_bad&type=img/png"> </img>
|
||||
<audio src="http://example.org/tests/content/base/test/file_CSP.sjs?testid=media_bad&type=audio/vorbis"></audio>
|
||||
<script src='http://example.org/tests/content/base/test/file_CSP.sjs?testid=script_bad&type=text/javascript'></script>
|
||||
<iframe src='http://example.org/tests/content/base/test/file_CSP.sjs?testid=frame_bad&content=FAIL'></iframe>
|
||||
<object width="10" height="10">
|
||||
<param name="movie" value="http://example.org/tests/content/base/test/file_CSP.sjs?testid=object_bad&type=application/x-shockwave-flash">
|
||||
<embed src="http://example.org/tests/content/base/test/file_CSP.sjs?testid=object_bad&type=application/x-shockwave-flash"></embed>
|
||||
</object>
|
||||
|
||||
<!-- these should load ok. :) -->
|
||||
<img src="file_CSP.sjs?testid=img_good&type=img/png" />
|
||||
<audio src="file_CSP.sjs?testid=media_good&type=audio/vorbis"></audio>
|
||||
<script src='file_CSP.sjs?testid=script_good&type=text/javascript'></script>
|
||||
<iframe src='file_CSP.sjs?testid=frame_good&content=PASS'></iframe>
|
||||
|
||||
<object width="10" height="10">
|
||||
<param name="movie" value="file_CSP.sjs?testid=object_good&type=application/x-shockwave-flash">
|
||||
<embed src="file_CSP.sjs?testid=object_good&type=application/x-shockwave-flash"></embed>
|
||||
</object>
|
||||
|
||||
<!-- XHR tests... they're taken care of in this script,
|
||||
and since the URI doesn't have any 'testid' values,
|
||||
it will just be ignored by the test framework. -->
|
||||
<script src='file_CSP_main.js'></script>
|
||||
|
||||
<!-- Support elements for the @font-face test -->
|
||||
<div class="div_arbitrary_good">arbitrary good</div>
|
||||
<div class="div_arbitrary_bad">arbitrary_bad</div>
|
||||
</body>
|
||||
</html>
|
16
content/base/test/file_CSP_main.js
Normal file
16
content/base/test/file_CSP_main.js
Normal file
@ -0,0 +1,16 @@
|
||||
// some javascript for the CSP XHR tests
|
||||
//
|
||||
|
||||
try {
|
||||
var xhr_good = new XMLHttpRequest();
|
||||
var xhr_good_uri ="http://localhost:8888/tests/content/base/test/file_CSP.sjs?testid=xhr_good";
|
||||
xhr_good.open("GET", xhr_good_uri, true);
|
||||
xhr_good.send(null);
|
||||
} catch(e) {}
|
||||
|
||||
try {
|
||||
var xhr_bad = new XMLHttpRequest();
|
||||
var xhr_bad_uri ="http://example.com/tests/content/base/test/file_CSP.sjs?testid=xhr_bad";
|
||||
xhr_bad.open("GET", xhr_bad_uri, true);
|
||||
xhr_bad.send(null);
|
||||
} catch(e) {}
|
127
content/base/test/test_CSP.html
Normal file
127
content/base/test/test_CSP.html
Normal file
@ -0,0 +1,127 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Content Security Policy Connections</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var path = "/tests/content/base/test/";
|
||||
|
||||
// These are test results: -1 means it hasn't run,
|
||||
// true/false is the pass/fail result.
|
||||
window.tests = {
|
||||
img_good: -1,
|
||||
img_bad: -1,
|
||||
style_good: -1,
|
||||
style_bad: -1,
|
||||
frame_good: -1,
|
||||
frame_bad: -1,
|
||||
script_good: -1,
|
||||
script_bad: -1,
|
||||
xhr_good: -1,
|
||||
xhr_bad: -1,
|
||||
media_good: -1,
|
||||
media_bad: -1,
|
||||
font_good: -1,
|
||||
font_bad: -1,
|
||||
object_good: -1,
|
||||
object_bad: -1,
|
||||
};
|
||||
|
||||
|
||||
// This is used to watch the blocked data bounce off CSP and allowed data
|
||||
// get sent out to the wire.
|
||||
function examiner() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var obsvc = Components.classes['@mozilla.org/observer-service;1']
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
obsvc.addObserver(this, "csp-on-violate-policy", false);
|
||||
obsvc.addObserver(this, "http-on-modify-request", false);
|
||||
}
|
||||
examiner.prototype = {
|
||||
observe: function(subject, topic, data) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
// subject should be an nsURI, and should be either allowed or blocked.
|
||||
if(!subject.QueryInterface)
|
||||
return;
|
||||
|
||||
var testpat = new RegExp("testid=([a-z0-9_]+)");
|
||||
|
||||
//_good things better be allowed!
|
||||
//_bad things better be stopped!
|
||||
|
||||
if (topic === "http-on-modify-request") {
|
||||
//these things were allowed by CSP
|
||||
var uri = subject.QueryInterface(Components.interfaces.nsIHttpChannel).URI;
|
||||
if (!testpat.test(uri.asciiSpec)) return;
|
||||
var testid = testpat.exec(uri.asciiSpec)[1];
|
||||
window.testResult(testid,
|
||||
/_good/.test(testid),
|
||||
uri.asciiSpec + " allowed by csp");
|
||||
|
||||
}
|
||||
|
||||
if(topic === "csp-on-violate-policy") {
|
||||
//these were blocked... record that they were blocked
|
||||
var uri = subject.QueryInterface(Components.interfaces.nsIURI);
|
||||
if (!testpat.test(uri.asciiSpec)) return;
|
||||
var testid = testpat.exec(uri.asciiSpec)[1];
|
||||
window.testResult(testid,
|
||||
/_bad/.test(testid),
|
||||
uri.asciiSpec + " blocked by \"" + data + "\"");
|
||||
}
|
||||
},
|
||||
|
||||
// must eventually call this to remove the listener,
|
||||
// or mochitests might get borked.
|
||||
remove: function() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var obsvc = Components.classes['@mozilla.org/observer-service;1']
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
obsvc.removeObserver(this, "csp-on-violate-policy");
|
||||
obsvc.removeObserver(this, "http-on-modify-request");
|
||||
}
|
||||
}
|
||||
|
||||
window.examiner = new examiner();
|
||||
|
||||
window.testResult = function(testname, result, msg) {
|
||||
|
||||
//test already complete.... forget it... remember the first result.
|
||||
if (window.tests[testname] != -1)
|
||||
return;
|
||||
|
||||
window.tests[testname] = result;
|
||||
is(result, true, testname + ' test: ' + msg);
|
||||
|
||||
// if any test is incomplete, keep waiting
|
||||
for (var v in window.tests)
|
||||
if(tests[v] == -1)
|
||||
return;
|
||||
|
||||
// ... otherwise, finish
|
||||
window.examiner.remove();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// save this for last so that our listeners are registered.
|
||||
// ... this loads the testbed of good and bad requests.
|
||||
document.getElementById('cspframe').src = 'file_CSP.sjs?main=1';
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -268,6 +268,7 @@ static void Shutdown();
|
||||
#endif
|
||||
|
||||
#include "nsGeolocation.h"
|
||||
#include "nsCSPService.h"
|
||||
|
||||
// Transformiix
|
||||
/* {0C351177-0159-4500-86B0-A219DFDE4258} */
|
||||
@ -848,6 +849,60 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGeolocation, Init)
|
||||
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsGeolocationService, nsGeolocationService::GetGeolocationService)
|
||||
|
||||
static NS_METHOD
|
||||
CSPServiceRegistration(nsIComponentManager *aCompMgr,
|
||||
nsIFile *aPath,
|
||||
const char *registryLocation,
|
||||
const char *componentType,
|
||||
const nsModuleComponentInfo *info)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsICategoryManager> catman;
|
||||
rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
|
||||
NS_GET_IID(nsICategoryManager),
|
||||
getter_AddRefs(catman));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsXPIDLCString previous;
|
||||
rv = catman->AddCategoryEntry("content-policy",
|
||||
"CSPService",
|
||||
CSPSERVICE_CONTRACTID,
|
||||
PR_TRUE,
|
||||
PR_TRUE,
|
||||
getter_Copies(previous));
|
||||
return rv;
|
||||
}
|
||||
|
||||
static NS_METHOD
|
||||
CSPServiceUnregistration(nsIComponentManager *aCompMgr,
|
||||
nsIFile *aPath,
|
||||
const char *registryLocation,
|
||||
const nsModuleComponentInfo *info){
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsICategoryManager> catman;
|
||||
rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
|
||||
NS_GET_IID(nsICategoryManager),
|
||||
getter_AddRefs(catman));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = catman->DeleteCategoryEntry("content-policy",
|
||||
"CSPService",
|
||||
PR_TRUE);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(CSPService)
|
||||
|
||||
// The list of components we register
|
||||
static const nsModuleComponentInfo gComponents[] = {
|
||||
#ifdef DEBUG
|
||||
@ -1453,6 +1508,12 @@ static const nsModuleComponentInfo gComponents[] = {
|
||||
"@mozilla.org/focus-manager;1",
|
||||
CreateFocusManager },
|
||||
|
||||
{ "Content Security Policy Service",
|
||||
CSPSERVICE_CID,
|
||||
CSPSERVICE_CONTRACTID,
|
||||
CSPServiceConstructor,
|
||||
CSPServiceRegistration,
|
||||
CSPServiceUnregistration },
|
||||
|
||||
{ "Event Listener Service",
|
||||
NS_EVENTLISTENERSERVICE_CID,
|
||||
|
Loading…
Reference in New Issue
Block a user