Security/CSP:Implementation
This is a collaboration page that is intended to help guide the process of implementing CSP in Firefox.
Parts:
- Component
- Each document that uses CSP has a CSP Component (CSPC) attached to it. This CSPC parses any policy, stores it, is responsible for reporting errors and handling content policy enforcement.
- CSP Service
- Each application has a singleton Content Security Policy Service (CSP-CPS) that delegates content policy decisions to each CSPC. It knows how to locate a CSPC instance for a given request, and for each ShouldLoad() call, decides which CSPC is responsible for the decision.
Additionally, hooks must be placed in the appropriate document-loading spots so that CSP can be created and initialized in a way that is properly enforceable.
Contents
The CSP Component (CSPC)
- Code Location
- $SRC/caps/src/contentSecurityPolicy.js
- Interface
- $SRC/caps/idl/IContentSecurityPolicy.idl
- Use
- One per document.
- Purpose
- To do the bulk of the CSP policy enforcement and parsing
On nsDocument load, a CSPC is created when the appropriate HTTP header was specified in the response *and* the document is a content document (not chrome, or system privileged).
//in nsDocument.cpp:StartDocumentLoad() nsAutoString cspHeaderValue; nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager(); nsIAtom* cspHeaderAtom = NS_NewAtom("x-content-security-policy"); this->GetHeaderData(cspHeaderAtom, cspHeaderValue); 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()) { // no CSP header present return NS_OK; } // mCSP is type (<nsICOMPtr> IContentSecurityPolicy) mCSP = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv); if(NS_FAILED(rv)) { return rv; } // Store the request context for violation reports nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel); mCSP->ScanRequestData(httpChannel); // Start parsing the policy nsCOMPtr<nsIURI> selfURI; aChannel->GetURI(getter_AddRefs(selfURI)); mCSP->RefinePolicy(cspHeaderValue, selfURI); // Check for frame-ancestor violation nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer); if(docShell != NULL) { PRBool safeAncestry = false; // PermitsAncestry sends violation reports when necessary rv = mCSP->PermitsAncestry(docShell, &safeAncestry); if(NS_FAILED(rv)) { return rv; } if(!safeAncestry) { aChannel->Cancel(NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY, 99)); } }
API
The CSPC has four methods:
void refinePolicy(in AString policyString, in nsIURI selfURI);
This method is called with a string representation of a CSP (e.g., "allow *") when a policy is encountered. It intersects the current policy with the provided one and returns a policy that is strict enough to satisfy both policies.
boolean permitsAncestry(in nsIDocShell docShell);
This method is called as the document is being loaded, but after the CSPC has been initialized and refined, to determine if it is enframed in a way violating the policy. If the document's load violates the "frame-ancestors" directive, a report is sent and the document is not rendered.
void scanRequestData(in nsIHttpChannel aChannel);
This method is 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.
short shouldLoad(in unsigned long aContentType, in nsIURI aContentLocation, in nsIURI aRequestOrigin, in nsISupports aContext, in ACString aMimeTypeGuess, in nsISupports aExtra);
This method is called by the CSP Service when a URI is requested. It queries the CSP policy structure (internal data representation of the policy) and returns true if the current CSP allows the load.
short shouldProcess(in unsigned long aContentType, in nsIURI aContentLocation, in nsIURI aRequestOrigin, in nsISupports aContext, in ACString aMimeType, in nsISupports aExtra);
This method is called by the CSP Service after a data at an URI has been retrieved. It is currently an inactive stub that always accepts the process request, but is available for future policy use.
The CSP Content Policy Service (CSP-CPS)
- Code Location
- $SRC/content/base/src/nsCSPService.*
- Use
- One per application
- Purpose
- Broker HTTP requests for appropriate CSP components.
This XPCOM service registers with the ContentPolicy service and delegates policy enforcement to any CSP components (documents) that have a CSP component.
Hooking Into Document Loading
This section describes how CSP is initialized when a document is loaded and was served with an X-CSP header.
In nsDocument::StartDocumentLoad(), an instance of the CSP component is created given the nsIChannel information. All the magic of CSP enforcement takes place from the CSP component instance.
The component is destroyed in nsDocument::Destroy().
Enforcing Base Restrictions
No-EVAL: Modifications to JSAPI
TODO
No-Inline-Script: Modifications to DOM
TODO