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 "nsIDOMHTMLDocument.h"
|
||||||
#include "nsIDOMHTMLElement.h"
|
#include "nsIDOMHTMLElement.h"
|
||||||
#include "nsIHttpChannel.h"
|
#include "nsIHttpChannel.h"
|
||||||
|
#include "nsIInterfaceRequestor.h"
|
||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
#include "nsIObjectInputStream.h"
|
#include "nsIObjectInputStream.h"
|
||||||
#include "nsIObjectOutputStream.h"
|
#include "nsIObjectOutputStream.h"
|
||||||
@ -26,6 +27,7 @@
|
|||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
#include "nsIPropertyBag2.h"
|
#include "nsIPropertyBag2.h"
|
||||||
#include "nsIScriptError.h"
|
#include "nsIScriptError.h"
|
||||||
|
#include "nsIWebNavigation.h"
|
||||||
#include "nsIWritablePropertyBag2.h"
|
#include "nsIWritablePropertyBag2.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "prlog.h"
|
#include "prlog.h"
|
||||||
@ -439,11 +441,118 @@ nsCSPContext::SetRequestContext(nsIURI* aSelfURI,
|
|||||||
return NS_OK;
|
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
|
NS_IMETHODIMP
|
||||||
nsCSPContext::PermitsAncestry(nsIDocShell* aDocShell, bool* outPermitsAncestry)
|
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;
|
*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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,6 +636,8 @@ CSP_DirectiveToContentType(enum CSPDirective aDir)
|
|||||||
case CSP_MEDIA_SRC: return nsIContentPolicy::TYPE_MEDIA;
|
case CSP_MEDIA_SRC: return nsIContentPolicy::TYPE_MEDIA;
|
||||||
case CSP_OBJECT_SRC: return nsIContentPolicy::TYPE_OBJECT;
|
case CSP_OBJECT_SRC: return nsIContentPolicy::TYPE_OBJECT;
|
||||||
case CSP_FRAME_SRC: return nsIContentPolicy::TYPE_SUBDOCUMENT;
|
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:
|
// Fall through to error for the following Directives:
|
||||||
case CSP_DEFAULT_SRC:
|
case CSP_DEFAULT_SRC:
|
||||||
|
@ -49,22 +49,24 @@ enum CSPDirective {
|
|||||||
CSP_FONT_SRC,
|
CSP_FONT_SRC,
|
||||||
CSP_CONNECT_SRC,
|
CSP_CONNECT_SRC,
|
||||||
CSP_REPORT_URI,
|
CSP_REPORT_URI,
|
||||||
|
CSP_FRAME_ANCESTORS,
|
||||||
// CSP_LAST_DIRECTIVE_VALUE always needs to be the last element in the enum
|
// 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.
|
// because we use it to calculate the size for the char* array.
|
||||||
CSP_LAST_DIRECTIVE_VALUE
|
CSP_LAST_DIRECTIVE_VALUE
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* CSPStrDirectives[] = {
|
static const char* CSPStrDirectives[] = {
|
||||||
"default-src", // CSP_DEFAULT_SRC = 0
|
"default-src", // CSP_DEFAULT_SRC = 0
|
||||||
"script-src", // CSP_SCRIPT_SRC
|
"script-src", // CSP_SCRIPT_SRC
|
||||||
"object-src", // CSP_OBJECT_SRC
|
"object-src", // CSP_OBJECT_SRC
|
||||||
"style-src", // CSP_STYLE_SRC
|
"style-src", // CSP_STYLE_SRC
|
||||||
"img-src", // CSP_IMG_SRC
|
"img-src", // CSP_IMG_SRC
|
||||||
"media-src", // CSP_MEDIA_SRC
|
"media-src", // CSP_MEDIA_SRC
|
||||||
"frame-src", // CSP_FRAME_SRC
|
"frame-src", // CSP_FRAME_SRC
|
||||||
"font-src", // CSP_FONT_SRC
|
"font-src", // CSP_FONT_SRC
|
||||||
"connect-src", // CSP_CONNECT_SRC
|
"connect-src", // CSP_CONNECT_SRC
|
||||||
"report-uri", // CSP_REPORT_URI
|
"report-uri", // CSP_REPORT_URI
|
||||||
|
"frame-ancestors" // CSP_FRAME_ANCESTORS
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const char* CSP_EnumToDirective(enum CSPDirective aDir)
|
inline const char* CSP_EnumToDirective(enum CSPDirective aDir)
|
||||||
|
@ -667,6 +667,28 @@ nsresult TestGoodGeneratedPolicies() {
|
|||||||
"script-src http://policy-uri" },
|
"script-src http://policy-uri" },
|
||||||
{ "img-src 'self'; ",
|
{ "img-src 'self'; ",
|
||||||
"img-src http://www.selfuri.com" },
|
"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);
|
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||||
|
Loading…
Reference in New Issue
Block a user