mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
Bug 994320 - Implement permitsAncestry CSP in C++. r=ckerschb,grobinson
This commit is contained in:
parent
dcca40c212
commit
2643314acb
@ -18,6 +18,7 @@
|
||||
#include "nsIDOMHTMLDocument.h"
|
||||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
@ -26,6 +27,7 @@
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIPropertyBag2.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsString.h"
|
||||
#include "prlog.h"
|
||||
@ -439,11 +441,118 @@ nsCSPContext::SetRequestContext(nsIURI* aSelfURI,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the given docshell, determines if this CSP context allows the
|
||||
* ancestry.
|
||||
*
|
||||
* In order to determine the URI of the parent document (one causing the load
|
||||
* of this protected document), this function obtains the docShellTreeItem,
|
||||
* then walks up the hierarchy until it finds a privileged (chrome) tree item.
|
||||
* Getting the parent's URI looks like this in pseudocode:
|
||||
*
|
||||
* nsIDocShell->QI(nsIInterfaceRequestor)
|
||||
* ->GI(nsIDocShellTreeItem)
|
||||
* ->QI(nsIInterfaceRequestor)
|
||||
* ->GI(nsIWebNavigation)
|
||||
* ->GetCurrentURI();
|
||||
*
|
||||
* aDocShell is the docShell for the protected document.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsCSPContext::PermitsAncestry(nsIDocShell* aDocShell, bool* outPermitsAncestry)
|
||||
{
|
||||
// For now, we allows permitsAncestry, this will be fixed in Bug 994320
|
||||
nsresult rv;
|
||||
|
||||
// Can't check ancestry without a docShell.
|
||||
if (aDocShell == nullptr) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*outPermitsAncestry = true;
|
||||
|
||||
// extract the ancestry as an array
|
||||
nsCOMArray<nsIURI> ancestorsArray;
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> ir(do_QueryInterface(aDocShell));
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_GetInterface(ir));
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
|
||||
nsCOMPtr<nsIWebNavigation> webNav;
|
||||
nsCOMPtr<nsIURI> currentURI;
|
||||
nsCOMPtr<nsIURI> uriClone;
|
||||
|
||||
// iterate through each docShell parent item
|
||||
while (NS_SUCCEEDED(treeItem->GetParent(getter_AddRefs(parentTreeItem))) &&
|
||||
parentTreeItem != nullptr) {
|
||||
ir = do_QueryInterface(parentTreeItem);
|
||||
NS_ASSERTION(ir, "Could not QI docShellTreeItem to nsIInterfaceRequestor");
|
||||
|
||||
webNav = do_GetInterface(ir);
|
||||
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
|
||||
|
||||
rv = webNav->GetCurrentURI(getter_AddRefs(currentURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (currentURI) {
|
||||
// stop when reaching chrome
|
||||
bool isChrome = false;
|
||||
rv = currentURI->SchemeIs("chrome", &isChrome);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isChrome) { break; }
|
||||
|
||||
// delete the userpass from the URI.
|
||||
rv = currentURI->CloneIgnoringRef(getter_AddRefs(uriClone));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = uriClone->SetUserPass(EmptyCString());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
#ifdef PR_LOGGING
|
||||
{
|
||||
nsAutoCString spec;
|
||||
uriClone->GetSpec(spec);
|
||||
CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, found ancestor: %s", spec.get()));
|
||||
}
|
||||
#endif
|
||||
ancestorsArray.AppendElement(uriClone);
|
||||
}
|
||||
|
||||
// next ancestor
|
||||
treeItem = parentTreeItem;
|
||||
}
|
||||
|
||||
nsAutoString violatedDirective;
|
||||
|
||||
// Now that we've got the ancestry chain in ancestorsArray, time to check
|
||||
// them against any CSP.
|
||||
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
||||
for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
|
||||
// TODO(sid) the mapping from frame-ancestors context to TYPE_DOCUMENT is
|
||||
// forced. while this works for now, we will implement something in
|
||||
// bug 999656.
|
||||
#ifdef PR_LOGGING
|
||||
{
|
||||
nsAutoCString spec;
|
||||
ancestorsArray[a]->GetSpec(spec);
|
||||
CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s", spec.get()));
|
||||
}
|
||||
#endif
|
||||
if (!mPolicies[i]->permits(nsIContentPolicy::TYPE_DOCUMENT,
|
||||
ancestorsArray[a],
|
||||
EmptyString(), // no nonce
|
||||
violatedDirective)) {
|
||||
// Policy is violated
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
NS_ENSURE_TRUE(observerService, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
observerService->NotifyObservers(ancestorsArray[a],
|
||||
CSP_VIOLATION_TOPIC,
|
||||
violatedDirective.get());
|
||||
// TODO(sid) generate violation reports and remove NotifyObservers
|
||||
// call. (in bug 994322)
|
||||
// TODO(sid) implement logic for report-only (in bug 994322)
|
||||
*outPermitsAncestry = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -636,6 +636,8 @@ CSP_DirectiveToContentType(enum CSPDirective aDir)
|
||||
case CSP_MEDIA_SRC: return nsIContentPolicy::TYPE_MEDIA;
|
||||
case CSP_OBJECT_SRC: return nsIContentPolicy::TYPE_OBJECT;
|
||||
case CSP_FRAME_SRC: return nsIContentPolicy::TYPE_SUBDOCUMENT;
|
||||
// TODO(sid): fix this mapping to be more precise (bug 999656)
|
||||
case CSP_FRAME_ANCESTORS: return nsIContentPolicy::TYPE_DOCUMENT;
|
||||
|
||||
// Fall through to error for the following Directives:
|
||||
case CSP_DEFAULT_SRC:
|
||||
|
@ -49,22 +49,24 @@ enum CSPDirective {
|
||||
CSP_FONT_SRC,
|
||||
CSP_CONNECT_SRC,
|
||||
CSP_REPORT_URI,
|
||||
CSP_FRAME_ANCESTORS,
|
||||
// CSP_LAST_DIRECTIVE_VALUE always needs to be the last element in the enum
|
||||
// because we use it to calculate the size for the char* array.
|
||||
CSP_LAST_DIRECTIVE_VALUE
|
||||
};
|
||||
|
||||
static const char* CSPStrDirectives[] = {
|
||||
"default-src", // CSP_DEFAULT_SRC = 0
|
||||
"script-src", // CSP_SCRIPT_SRC
|
||||
"object-src", // CSP_OBJECT_SRC
|
||||
"style-src", // CSP_STYLE_SRC
|
||||
"img-src", // CSP_IMG_SRC
|
||||
"media-src", // CSP_MEDIA_SRC
|
||||
"frame-src", // CSP_FRAME_SRC
|
||||
"font-src", // CSP_FONT_SRC
|
||||
"connect-src", // CSP_CONNECT_SRC
|
||||
"report-uri", // CSP_REPORT_URI
|
||||
"default-src", // CSP_DEFAULT_SRC = 0
|
||||
"script-src", // CSP_SCRIPT_SRC
|
||||
"object-src", // CSP_OBJECT_SRC
|
||||
"style-src", // CSP_STYLE_SRC
|
||||
"img-src", // CSP_IMG_SRC
|
||||
"media-src", // CSP_MEDIA_SRC
|
||||
"frame-src", // CSP_FRAME_SRC
|
||||
"font-src", // CSP_FONT_SRC
|
||||
"connect-src", // CSP_CONNECT_SRC
|
||||
"report-uri", // CSP_REPORT_URI
|
||||
"frame-ancestors" // CSP_FRAME_ANCESTORS
|
||||
};
|
||||
|
||||
inline const char* CSP_EnumToDirective(enum CSPDirective aDir)
|
||||
|
@ -667,6 +667,28 @@ nsresult TestGoodGeneratedPolicies() {
|
||||
"script-src http://policy-uri" },
|
||||
{ "img-src 'self'; ",
|
||||
"img-src http://www.selfuri.com" },
|
||||
{ "frame-ancestors foo-bar.com",
|
||||
"frame-ancestors http://foo-bar.com" },
|
||||
{ "frame-ancestors http://a.com",
|
||||
"frame-ancestors http://a.com" },
|
||||
{ "frame-ancestors 'self'",
|
||||
"frame-ancestors http://www.selfuri.com" },
|
||||
{ "frame-ancestors http://self.com:88",
|
||||
"frame-ancestors http://self.com:88" },
|
||||
{ "frame-ancestors http://a.b.c.d.e.f.g.h.i.j.k.l.x.com",
|
||||
"frame-ancestors http://a.b.c.d.e.f.g.h.i.j.k.l.x.com" },
|
||||
{ "frame-ancestors https://self.com:34",
|
||||
"frame-ancestors https://self.com:34" },
|
||||
{ "default-src 'none'; frame-ancestors 'self'",
|
||||
"default-src 'none'; frame-ancestors http://www.selfuri.com" },
|
||||
{ "frame-ancestors http://self:80",
|
||||
"frame-ancestors http://self:80" },
|
||||
{ "frame-ancestors http://self.com/bar",
|
||||
"frame-ancestors http://self.com" },
|
||||
{ "default-src 'self'; frame-ancestors 'self'",
|
||||
"default-src http://www.selfuri.com; frame-ancestors http://www.selfuri.com" },
|
||||
{ "frame-ancestors http://bar.com/foo.png",
|
||||
"frame-ancestors http://bar.com" },
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
|
Loading…
Reference in New Issue
Block a user