Use principals instead of URIs for same-origin checks.

b=159348, r=bz, sr=jst, a=asa


git-svn-id: svn://10.0.0.236/trunk@126081 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
sicking%bigfoot.com
2002-07-30 21:26:32 +00:00
parent cb1c633775
commit 9f524ba3a3
10 changed files with 219 additions and 88 deletions

View File

@@ -218,6 +218,13 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
[noscript] void checkSameOriginURI(in nsIURI aSourceURI,
in nsIURI aTargetURI);
/**
* Returns OK if aSourcePrincipal and aTargetPrincipal
* have the same "origin" (scheme, host, and port).
*/
[noscript] void checkSameOriginPrincipal(in nsIPrincipal aSourcePrincipal,
in nsIPrincipal aTargetPrincipal);
};
%{C++

View File

@@ -556,6 +556,15 @@ nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
return NS_OK;
}
NS_IMETHODIMP
nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSourcePrincipal,
nsIPrincipal* aTargetPrincipal)
{
return CheckSameOriginDOMProp(aSourcePrincipal, aTargetPrincipal,
nsIXPCSecurityManager::ACCESS_SET_PROPERTY);
}
nsresult
nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
nsIXPCNativeCallContext* aCallContext,

View File

@@ -67,6 +67,7 @@ class nsINodeInfoManager;
class nsINameSpaceManager;
class nsIDocument;
class nsIURI;
class nsIPrincipal;
// IID for the nsINodeInfo interface
@@ -287,6 +288,11 @@ public:
*/
NS_IMETHOD GetDocument(nsIDocument*& aDocument) const = 0;
/*
* Retrieve a pointer to the principal for the document of this node info.
*/
NS_IMETHOD GetDocumentPrincipal(nsIPrincipal** aPrincipal) const = 0;
protected:
/*
* nsNodeInfoInner is used for two things:
@@ -368,15 +374,15 @@ public:
NS_IMETHOD GetDocument(nsIDocument*& aDocument) = 0;
/**
* Gets the url of the document associated with this.
* Gets the principal of the document associated with this.
*/
NS_IMETHOD GetDocumentURL(nsIURI** aURL) = 0;
NS_IMETHOD GetDocumentPrincipal(nsIPrincipal** aPrincipal) = 0;
/**
* Sets the url of the nodeinfo manager. This should only be called when
* this nodeinfo manager isn't connected to an nsIDocument.
* Sets the principal of the nodeinfo manager. This should only be called
* when this nodeinfo manager isn't connected to an nsIDocument.
*/
NS_IMETHOD SetDocumentURL(nsIURI* aURL) = 0;
NS_IMETHOD SetDocumentPrincipal(nsIPrincipal* aPrincipal) = 0;
};

View File

@@ -379,12 +379,12 @@ nsContentUtils::CheckSameOrigin(nsIDOMNode *aTrustedNode,
NS_PRECONDITION(aTrustedNode, "There must be a trusted node");
/*
* Get hold of each node's document or uri
* Get hold of each node's document or principal
*/
// In most cases this is a document, so lets try that first
nsCOMPtr<nsIDocument> trustedDoc = do_QueryInterface(aTrustedNode);
nsCOMPtr<nsIURI> trustedUri;
nsCOMPtr<nsIPrincipal> trustedPrincipal;
if (!trustedDoc) {
#ifdef DEBUG
@@ -396,7 +396,7 @@ nsContentUtils::CheckSameOrigin(nsIDOMNode *aTrustedNode,
aTrustedNode->GetOwnerDocument(getter_AddRefs(domDoc));
if (!domDoc) {
// In theory this should never happen. But since theory and reality are
// different for XUL elements we'll try to get the URI from the
// different for XUL elements we'll try to get the principal from the
// nsINodeInfoManager.
nsCOMPtr<nsIContent> cont = do_QueryInterface(aTrustedNode);
@@ -406,12 +406,11 @@ nsContentUtils::CheckSameOrigin(nsIDOMNode *aTrustedNode,
cont->GetNodeInfo(*getter_AddRefs(ni));
NS_ENSURE_TRUE(ni, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsINodeInfoManager> nimgr;
ni->GetNodeInfoManager(*getter_AddRefs(nimgr));
nimgr->GetDocumentURL(getter_AddRefs(trustedUri));
ni->GetDocumentPrincipal(getter_AddRefs(trustedPrincipal));
if (!trustedUri) {
// Can't get uri of aTrustedNode so we can't check security against it
if (!trustedPrincipal) {
// Can't get principal of aTrustedNode so we can't check security
// against it
return NS_ERROR_UNEXPECTED;
}
@@ -429,7 +428,7 @@ nsContentUtils::CheckSameOrigin(nsIDOMNode *aTrustedNode,
nsCOMPtr<nsIContent> content = do_QueryInterface(aUnTrustedNode);
nsCOMPtr<nsIDocument> unTrustedDoc;
nsCOMPtr<nsIURI> unTrustedUri;
nsCOMPtr<nsIPrincipal> unTrustedPrincipal;
if (!content) {
unTrustedDoc = do_QueryInterface(aUnTrustedNode);
@@ -447,21 +446,21 @@ nsContentUtils::CheckSameOrigin(nsIDOMNode *aTrustedNode,
nsCOMPtr<nsIDOMDocument> domDoc;
aUnTrustedNode->GetOwnerDocument(getter_AddRefs(domDoc));
if (!domDoc) {
// if we can't get a doc then lets try to get uri through nodeinfo
// if we can't get a doc then lets try to get principal through nodeinfo
// manager
nsCOMPtr<nsINodeInfo> ni;
content->GetNodeInfo(*getter_AddRefs(ni));
if (!ni) {
// we can't get to the uri so we'll give up and give the caller access
// we can't get to the principal so we'll give up and give the caller
// access
return NS_OK;
}
nsCOMPtr<nsINodeInfoManager> nimgr;
ni->GetNodeInfoManager(*getter_AddRefs(nimgr));
nimgr->GetDocumentURL(getter_AddRefs(unTrustedUri));
if (!unTrustedUri) {
// we can't get to the uri so we'll give up and give the caller access
ni->GetDocumentPrincipal(getter_AddRefs(unTrustedPrincipal));
if (!unTrustedPrincipal) {
// we can't get to the principal so we'll give up and give the caller access
return NS_OK;
}
@@ -473,31 +472,31 @@ nsContentUtils::CheckSameOrigin(nsIDOMNode *aTrustedNode,
}
/*
* Compare the uris
* Compare the principals
*/
// If they are in the same document then everything is just fine
if (trustedDoc == unTrustedDoc && trustedDoc)
return NS_OK;
if (!trustedUri) {
trustedDoc->GetDocumentURL(getter_AddRefs(trustedUri));
// If the trusted node doesn't have a uri we can't check security against it
if (!trustedUri) {
if (!trustedPrincipal) {
trustedDoc->GetPrincipal(getter_AddRefs(trustedPrincipal));
if (!trustedPrincipal) {
// If the trusted node doesn't have a principal we can't check security against it
return NS_ERROR_DOM_SECURITY_ERR;
}
}
// Chrome can do anything
PRBool isChrome;
nsresult rv = trustedUri->SchemeIs("chrome", &isChrome);
if (NS_SUCCEEDED(rv) && isChrome) {
return NS_OK;
}
if (!unTrustedUri) {
unTrustedDoc->GetDocumentURL(getter_AddRefs(unTrustedUri));
// If the untrusted node doesn't have a uri we'll allow it to be accessed.
if (!unTrustedUri) {
if (!unTrustedPrincipal) {
unTrustedDoc->GetPrincipal(getter_AddRefs(unTrustedPrincipal));
if (!unTrustedDoc) {
// We can't get hold of the principal for this node. This should happen
// very rarely, like for textnodes out of the tree and <option>s created
// using 'new Option'.
// If we didn't allow access to nodes like this you wouldn't be able to
// insert these nodes into a document.
return NS_OK;
}
}
@@ -508,24 +507,38 @@ nsContentUtils::CheckSameOrigin(nsIDOMNode *aTrustedNode,
return NS_OK;
}
return sSecurityManager->CheckSameOriginURI(trustedUri, unTrustedUri);
return sSecurityManager->CheckSameOriginPrincipal(trustedPrincipal,
unTrustedPrincipal);
}
// static
PRBool
nsContentUtils::CanCallerAccess(nsIDOMNode *aNode)
{
if (!sSecurityManager) {
// No security manager available, let any calls go through...
return PR_TRUE;
}
nsCOMPtr<nsIPrincipal> subjectPrincipal;
sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
if (!subjectPrincipal) {
// we're running as system, grant access to the node.
return PR_TRUE;
}
// Make sure that this is a real node. We do this by first QI'ing to
// nsIContent (which is important performance wise) and if that QI
// fails we QI to nsIDocument. If both those QI's fail we won't let
// the caller access this unknown node.
nsCOMPtr<nsIPrincipal> principal;
nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
nsCOMPtr<nsIDocument> doc;
if (!content) {
doc = do_QueryInterface(aNode);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aNode);
if (!doc) {
// aNode is neither a nsIContent nor an nsIDocument, something
@@ -535,31 +548,41 @@ nsContentUtils::CanCallerAccess(nsIDOMNode *aNode)
return PR_FALSE;
}
doc->GetPrincipal(getter_AddRefs(principal));
}
if (!doc) {
else {
nsCOMPtr<nsIDOMDocument> domDoc;
aNode->GetOwnerDocument(getter_AddRefs(domDoc));
if (!domDoc) {
// aNode is not part of a document, let any caller access it.
return PR_TRUE;
nsCOMPtr<nsINodeInfo> ni;
content->GetNodeInfo(*getter_AddRefs(ni));
if (!ni) {
// aNode is not part of a document, let any caller access it.
return PR_TRUE;
}
ni->GetDocumentPrincipal(getter_AddRefs(principal));
}
else {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
NS_ASSERTION(doc, "QI to nsIDocument failed");
doc->GetPrincipal(getter_AddRefs(principal));
}
doc = do_QueryInterface(domDoc);
NS_ASSERTION(doc, "QI to nsIDocument failed");
}
if (!sSecurityManager) {
// No security manager available, let any calls go through...
if (!principal) {
// We can't get hold of the principal for this node. This should happen
// very rarely, like for textnodes out of the tree and <option>s created
// using 'new Option'.
// If we didn't allow access to nodes like this you wouldn't be able to
// insert these nodes into a document.
return PR_TRUE;
}
nsCOMPtr<nsIURI> uri;
doc->GetDocumentURL(getter_AddRefs(uri));
nsresult rv = sSecurityManager->CheckSameOrigin(nsnull, uri);
nsresult rv = sSecurityManager->CheckSameOriginPrincipal(subjectPrincipal,
principal);
return NS_SUCCEEDED(rv);
}

View File

@@ -325,3 +325,8 @@ nsNodeInfo::GetDocument(nsIDocument*& aDocument) const
return mOwnerManager->GetDocument(aDocument);
}
NS_IMETHODIMP
nsNodeInfo::GetDocumentPrincipal(nsIPrincipal** aPrincipal) const
{
return mOwnerManager->GetDocumentPrincipal(aPrincipal);
}

View File

@@ -72,6 +72,7 @@ public:
NS_IMETHOD NameChanged(nsIAtom *aName, nsINodeInfo*& aResult);
NS_IMETHOD PrefixChanged(nsIAtom *aPrefix, nsINodeInfo*& aResult);
NS_IMETHOD GetDocument(nsIDocument*& aDocument) const;
NS_IMETHOD GetDocumentPrincipal(nsIPrincipal** aPrincipal) const;
// nsNodeInfo
nsNodeInfo();

View File

@@ -42,6 +42,7 @@
#include "nsString.h"
#include "nsIAtom.h"
#include "nsIDocument.h"
#include "nsIPrincipal.h"
nsNodeInfoManager* nsNodeInfoManager::gAnonymousNodeInfoManager = nsnull;
PRUint32 nsNodeInfoManager::gNodeManagerCount = 0;
@@ -155,7 +156,7 @@ nsNodeInfoManager::Init(nsIDocument *aDocument,
mDocument = aDocument;
mNameSpaceManager = aNameSpaceManager;
if (aDocument) {
mDocumentURL = nsnull;
mPrincipal = nsnull;
}
return NS_OK;
@@ -166,7 +167,17 @@ NS_IMETHODIMP
nsNodeInfoManager::DropDocumentReference()
{
if (mDocument) {
mDocument->GetDocumentURL(getter_AddRefs(mDocumentURL));
// If the document has a uri we'll ask for it's principal. Otherwise we'll
// consider this document 'anonymous'. We don't want to call GetPrincipal
// on a document that doesn't have a URI since that'll give an assertion
// that we're creating a principal without having a uri.
// This happens in a few cases where a document is created and then
// immediately dropped without ever getting a URI.
nsCOMPtr<nsIURI> docUri;
mDocument->GetDocumentURL(getter_AddRefs(docUri));
if (docUri) {
mDocument->GetPrincipal(getter_AddRefs(mPrincipal));
}
}
mDocument = nsnull;
@@ -335,25 +346,33 @@ nsNodeInfoManager::GetDocument(nsIDocument*& aDocument)
}
NS_IMETHODIMP
nsNodeInfoManager::GetDocumentURL(nsIURI** aURL)
nsNodeInfoManager::GetDocumentPrincipal(nsIPrincipal** aPrincipal)
{
NS_ENSURE_ARG_POINTER(aURL);
NS_ASSERTION(!mDocument || !mDocumentURL,
"how'd we end up with both a document and a url?");
NS_ENSURE_ARG_POINTER(aPrincipal);
NS_ASSERTION(!mDocument || !mPrincipal,
"how'd we end up with both a document and a principal?");
if (mDocument) {
return mDocument->GetDocumentURL(aURL);
// If the document has a uri we'll ask for it's principal. Otherwise we'll
// consider this document 'anonymous'
nsCOMPtr<nsIURI> docUri;
mDocument->GetDocumentURL(getter_AddRefs(docUri));
if (!docUri) {
*aPrincipal = nsnull;
return NS_OK;
}
return mDocument->GetPrincipal(aPrincipal);
}
*aURL = mDocumentURL;
NS_IF_ADDREF(*aURL);
*aPrincipal = mPrincipal;
NS_IF_ADDREF(*aPrincipal);
return NS_OK;
}
NS_IMETHODIMP
nsNodeInfoManager::SetDocumentURL(nsIURI* aURL)
nsNodeInfoManager::SetDocumentPrincipal(nsIPrincipal* aPrincipal)
{
NS_ENSURE_FALSE(mDocument, NS_ERROR_UNEXPECTED);
mDocumentURL = aURL;
mPrincipal = aPrincipal;
return NS_OK;
}

View File

@@ -44,6 +44,7 @@
#include "nsCOMPtr.h"
#include "plhash.h"
#include "nsIURI.h"
#include "nsIPrincipal.h"
class nsNodeInfo;
@@ -71,8 +72,8 @@ public:
nsINodeInfo*& aNodeInfo);
NS_IMETHOD GetNamespaceManager(nsINameSpaceManager*& aNameSpaceManager);
NS_IMETHOD GetDocument(nsIDocument*& aDocument);
NS_IMETHOD GetDocumentURL(nsIURI** aURL);
NS_IMETHOD SetDocumentURL(nsIURI* aURL);
NS_IMETHOD GetDocumentPrincipal(nsIPrincipal** aPrincipal);
NS_IMETHOD SetDocumentPrincipal(nsIPrincipal* aPrincipal);
// nsNodeInfoManager
nsNodeInfoManager();
@@ -91,7 +92,7 @@ private:
PLHashTable *mNodeInfoHash;
nsCOMPtr<nsINameSpaceManager> mNameSpaceManager;
nsIDocument *mDocument; // WEAK
nsCOMPtr<nsIURI> mDocumentURL;
nsCOMPtr<nsIPrincipal> mPrincipal;
/*
* gAnonymousNodeInfoManager is a global nodeinfo manager used for nodes

View File

@@ -341,8 +341,16 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
if (! securityManager)
return NS_ERROR_FAILURE;
rv |= securityManager->GetCodebasePrincipal(mURI, getter_AddRefs(mDocumentPrincipal));
rv |= NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(mDocumentPrincipal));
if (!mDocumentPrincipal) {
// XXX This should be handled by the security manager, see bug 160042
PRBool isChrome = PR_FALSE;
if (NS_SUCCEEDED(mURI->SchemeIs("chrome", &isChrome)) && isChrome)
rv |= securityManager->GetSystemPrincipal(getter_AddRefs(mDocumentPrincipal));
else
rv |= securityManager->GetCodebasePrincipal(mURI, getter_AddRefs(mDocumentPrincipal));
}
mNodeInfoManager->SetDocumentPrincipal(mDocumentPrincipal);
// nsIScriptGlobalObject mGlobalObject
mGlobalObject = new nsXULPDGlobalObject();
@@ -440,9 +448,17 @@ nsXULPrototypeDocument::GetURI(nsIURI** aResult)
NS_IMETHODIMP
nsXULPrototypeDocument::SetURI(nsIURI* aURI)
{
NS_PRECONDITION(mNodeInfoManager, "missing nodeInfoManager");
NS_ASSERTION(!mURI, "Can't change the uri of a xul prototype document");
if (mURI)
return NS_ERROR_ALREADY_INITIALIZED;
mURI = aURI;
mNodeInfoManager->SetDocumentURL(aURI);
if (!mDocumentPrincipal) {
// If the document doesn't have a principal yet we'll force the creation of one
// so that mNodeInfoManager properly gets one.
nsCOMPtr<nsIPrincipal> principal;
GetDocumentPrincipal(getter_AddRefs(principal));
}
return NS_OK;
}
@@ -527,6 +543,7 @@ nsXULPrototypeDocument::SetHeaderData(nsIAtom* aField, const nsAString& aData)
NS_IMETHODIMP
nsXULPrototypeDocument::GetDocumentPrincipal(nsIPrincipal** aResult)
{
NS_PRECONDITION(mNodeInfoManager, "missing nodeInfoManager");
if (!mDocumentPrincipal) {
nsresult rv;
nsCOMPtr<nsIScriptSecurityManager> securityManager =
@@ -535,10 +552,17 @@ nsXULPrototypeDocument::GetDocumentPrincipal(nsIPrincipal** aResult)
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
rv = securityManager->GetCodebasePrincipal(mURI, getter_AddRefs(mDocumentPrincipal));
// XXX This should be handled by the security manager, see bug 160042
PRBool isChrome = PR_FALSE;
if (NS_SUCCEEDED(mURI->SchemeIs("chrome", &isChrome)) && isChrome)
rv = securityManager->GetSystemPrincipal(getter_AddRefs(mDocumentPrincipal));
else
rv = securityManager->GetCodebasePrincipal(mURI, getter_AddRefs(mDocumentPrincipal));
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
mNodeInfoManager->SetDocumentPrincipal(mDocumentPrincipal);
}
*aResult = mDocumentPrincipal;
@@ -550,7 +574,9 @@ nsXULPrototypeDocument::GetDocumentPrincipal(nsIPrincipal** aResult)
NS_IMETHODIMP
nsXULPrototypeDocument::SetDocumentPrincipal(nsIPrincipal* aPrincipal)
{
NS_PRECONDITION(mNodeInfoManager, "missing nodeInfoManager");
mDocumentPrincipal = aPrincipal;
mNodeInfoManager->SetDocumentPrincipal(aPrincipal);
return NS_OK;
}

View File

@@ -38,6 +38,8 @@
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIContent.h"
#include "nsIPrincipal.h"
#include "nsINodeInfo.h"
#endif
/**
@@ -323,44 +325,76 @@ nsIScriptSecurityManager *gTxSecurityManager = 0;
// static
PRBool URIUtils::CanCallerAccess(nsIDOMNode *aNode)
{
if (!gTxSecurityManager) {
// No security manager available, let any calls go through...
return PR_TRUE;
}
nsCOMPtr<nsIPrincipal> subjectPrincipal;
gTxSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
if (!subjectPrincipal) {
// we're running as system, grant access to the node.
return PR_TRUE;
}
// Make sure that this is a real node. We do this by first QI'ing to
// nsIContent (which is important performance wise) and if that QI
// fails we QI to nsIDocument. If both those QI's fail we won't let
// the caller access this unknown node.
nsCOMPtr<nsIDocument> doc;
nsCOMPtr<nsIPrincipal> principal;
nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
if (!content) {
doc = do_QueryInterface(aNode);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aNode);
if (!doc) {
// aNode is neither a nsIContent nor an nsIDocument, something
// weird is going on...
NS_ERROR("aNode is neither an nsIContent nor an nsIDocument!");
return PR_FALSE;
}
doc->GetPrincipal(getter_AddRefs(principal));
}
if (!doc) {
else {
nsCOMPtr<nsIDOMDocument> domDoc;
aNode->GetOwnerDocument(getter_AddRefs(domDoc));
if (!domDoc) {
// aNode is not part of a document, let any caller access it.
return PR_TRUE;
nsCOMPtr<nsINodeInfo> ni;
content->GetNodeInfo(*getter_AddRefs(ni));
if (!ni) {
// aNode is not part of a document, let any caller access it.
return PR_TRUE;
}
ni->GetDocumentPrincipal(getter_AddRefs(principal));
}
else {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
NS_ASSERTION(doc, "QI to nsIDocument failed");
doc->GetPrincipal(getter_AddRefs(principal));
}
doc = do_QueryInterface(domDoc);
NS_ASSERTION(doc, "QI to nsIDocument failed");
}
if (!gTxSecurityManager) {
// No security manager available, let any calls go through...
if (!principal) {
// We can't get hold of the principal for this node. This should happen
// very rarely, like for textnodes out of the tree and <option>s created
// using 'new Option'.
// If we didn't allow access to nodes like this you wouldn't be able to
// insert these nodes into a document.
return PR_TRUE;
}
nsCOMPtr<nsIURI> uri;
doc->GetDocumentURL(getter_AddRefs(uri));
nsresult rv = gTxSecurityManager->CheckSameOriginPrincipal(subjectPrincipal,
principal);
return NS_SUCCEEDED(gTxSecurityManager->CheckSameOrigin(nsnull, uri));
return NS_SUCCEEDED(rv);
}