зеркало из https://github.com/mozilla/pjs.git
Bug 475636: Disallow refresh to javascript uris. r/sr=bz
--HG-- extra : rebase_source : 1fdfc3148c257aee22001be045258cc985ee027a
This commit is contained in:
Родитель
2d12dd4d03
Коммит
47266550e3
|
@ -727,6 +727,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
|
|||
nsCOMPtr<nsIInputStream> headersStream;
|
||||
nsCOMPtr<nsISupports> owner;
|
||||
PRBool inheritOwner = PR_FALSE;
|
||||
PRBool ownerIsExplicit = PR_FALSE;
|
||||
PRBool sendReferrer = PR_TRUE;
|
||||
nsCOMPtr<nsISHEntry> shEntry;
|
||||
nsXPIDLString target;
|
||||
|
@ -745,6 +746,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
|
|||
|
||||
aLoadInfo->GetOwner(getter_AddRefs(owner));
|
||||
aLoadInfo->GetInheritOwner(&inheritOwner);
|
||||
aLoadInfo->GetOwnerIsExplicit(&ownerIsExplicit);
|
||||
aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
|
||||
aLoadInfo->GetTarget(getter_Copies(target));
|
||||
aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
|
||||
|
@ -862,84 +864,99 @@ nsDocShell::LoadURI(nsIURI * aURI,
|
|||
("nsDocShell[%p]: loading from session history", this));
|
||||
#endif
|
||||
|
||||
rv = LoadHistoryEntry(shEntry, loadType);
|
||||
return LoadHistoryEntry(shEntry, loadType);
|
||||
}
|
||||
|
||||
// Perform the load...
|
||||
else {
|
||||
// We need an owner (a referring principal). 4 possibilities:
|
||||
// (1) If the system principal was passed in and we're a typeContent
|
||||
// docshell, inherit the principal from the current document
|
||||
// instead.
|
||||
// (2) In all other cases when the principal passed in is not null,
|
||||
// use that principal.
|
||||
// (3) If the caller has allowed inheriting from the current document,
|
||||
// or if we're being called from system code (eg chrome JS or pure
|
||||
// C++) then inheritOwner should be true and InternalLoad will get
|
||||
// an owner from the current document. If none of these things are
|
||||
// true, then
|
||||
// (4) we pass a null owner into the channel, and an owner will be
|
||||
// created later from the channel's internal data.
|
||||
//
|
||||
// NOTE: This all only works because the only thing the owner is used
|
||||
// for in InternalLoad is data:, javascript:, and about:blank
|
||||
// URIs. For other URIs this would all be dead wrong!
|
||||
nsCOMPtr<nsIScriptSecurityManager> secMan =
|
||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
|
||||
|
||||
// We need an owner (a referring principal).
|
||||
//
|
||||
// If ownerIsExplicit is not set there are 4 possibilities:
|
||||
// (1) If the system principal was passed in and we're a typeContent
|
||||
// docshell, inherit the principal from the current document
|
||||
// instead.
|
||||
// (2) In all other cases when the principal passed in is not null,
|
||||
// use that principal.
|
||||
// (3) If the caller has allowed inheriting from the current document,
|
||||
// or if we're being called from system code (eg chrome JS or pure
|
||||
// C++) then inheritOwner should be true and InternalLoad will get
|
||||
// an owner from the current document. If none of these things are
|
||||
// true, then
|
||||
// (4) we pass a null owner into the channel, and an owner will be
|
||||
// created later from the channel's internal data.
|
||||
//
|
||||
// If ownerIsExplicit *is* set, there are 4 possibilities
|
||||
// (1) If the system principal was passed in and we're a typeContent
|
||||
// docshell, return an error.
|
||||
// (2) In all other cases when the principal passed in is not null,
|
||||
// use that principal.
|
||||
// (3) If the caller has allowed inheriting from the current document,
|
||||
// then inheritOwner should be true and InternalLoad will get an owner
|
||||
// from the current document. If none of these things are true, then
|
||||
// (4) we pass a null owner into the channel, and an owner will be
|
||||
// created later from the channel's internal data.
|
||||
//
|
||||
// NOTE: This all only works because the only thing the owner is used
|
||||
// for in InternalLoad is data:, javascript:, and about:blank
|
||||
// URIs. For other URIs this would all be dead wrong!
|
||||
|
||||
nsCOMPtr<nsIScriptSecurityManager> secMan =
|
||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (owner && mItemType != typeChrome) {
|
||||
nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
|
||||
PRBool isSystem;
|
||||
rv = secMan->IsSystemPrincipal(ownerPrincipal, &isSystem);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (owner && mItemType != typeChrome) {
|
||||
nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
|
||||
PRBool isSystem;
|
||||
rv = secMan->IsSystemPrincipal(ownerPrincipal, &isSystem);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (isSystem) {
|
||||
owner = nsnull;
|
||||
inheritOwner = PR_TRUE;
|
||||
if (isSystem) {
|
||||
if (ownerIsExplicit) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
owner = nsnull;
|
||||
inheritOwner = PR_TRUE;
|
||||
}
|
||||
if (!owner && !inheritOwner) {
|
||||
// See if there's system or chrome JS code running
|
||||
rv = secMan->SubjectPrincipalIsSystem(&inheritOwner);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Set it back to false
|
||||
inheritOwner = PR_FALSE;
|
||||
}
|
||||
}
|
||||
if (!owner && !inheritOwner && !ownerIsExplicit) {
|
||||
// See if there's system or chrome JS code running
|
||||
rv = secMan->SubjectPrincipalIsSystem(&inheritOwner);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Set it back to false
|
||||
inheritOwner = PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 flags = 0;
|
||||
|
||||
if (inheritOwner)
|
||||
flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
|
||||
|
||||
if (!sendReferrer)
|
||||
flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP)
|
||||
flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD)
|
||||
flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER)
|
||||
flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
|
||||
|
||||
rv = InternalLoad(aURI,
|
||||
referrer,
|
||||
owner,
|
||||
flags,
|
||||
target.get(),
|
||||
nsnull, // No type hint
|
||||
postStream,
|
||||
headersStream,
|
||||
loadType,
|
||||
nsnull, // No SHEntry
|
||||
aFirstParty,
|
||||
nsnull, // No nsIDocShell
|
||||
nsnull); // No nsIRequest
|
||||
}
|
||||
|
||||
return rv;
|
||||
PRUint32 flags = 0;
|
||||
|
||||
if (inheritOwner)
|
||||
flags |= INTERNAL_LOAD_FLAGS_INHERIT_OWNER;
|
||||
|
||||
if (!sendReferrer)
|
||||
flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP)
|
||||
flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD)
|
||||
flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER)
|
||||
flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
|
||||
|
||||
return InternalLoad(aURI,
|
||||
referrer,
|
||||
owner,
|
||||
flags,
|
||||
target.get(),
|
||||
nsnull, // No type hint
|
||||
postStream,
|
||||
headersStream,
|
||||
loadType,
|
||||
nsnull, // No SHEntry
|
||||
aFirstParty,
|
||||
nsnull, // No nsIDocShell
|
||||
nsnull); // No nsIRequest
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -4576,41 +4593,42 @@ nsDocShell::ForceRefreshURI(nsIURI * aURI,
|
|||
*/
|
||||
loadInfo->SetReferrer(mCurrentURI);
|
||||
|
||||
/* Don't ever "guess" on which owner to use to avoid picking
|
||||
* the current owner.
|
||||
*/
|
||||
loadInfo->SetOwnerIsExplicit(PR_TRUE);
|
||||
|
||||
/* Check if this META refresh causes a redirection
|
||||
* to another site.
|
||||
*/
|
||||
PRBool equalUri = PR_FALSE;
|
||||
nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
|
||||
if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh) {
|
||||
if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
|
||||
aDelay <= REFRESH_REDIRECT_TIMER) {
|
||||
|
||||
/* It is a META refresh based redirection. Now check if it happened
|
||||
within the threshold time we have in mind(15000 ms as defined by
|
||||
REFRESH_REDIRECT_TIMER). If so, pass a REPLACE flag to LoadURI().
|
||||
/* It is a META refresh based redirection within the threshold time
|
||||
* we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
|
||||
* Pass a REPLACE flag to LoadURI().
|
||||
*/
|
||||
if (aDelay <= REFRESH_REDIRECT_TIMER) {
|
||||
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
|
||||
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
|
||||
|
||||
/* for redirects we mimic HTTP, which passes the
|
||||
* original referrer
|
||||
*/
|
||||
nsCOMPtr<nsIURI> internalReferrer;
|
||||
GetReferringURI(getter_AddRefs(internalReferrer));
|
||||
if (internalReferrer) {
|
||||
loadInfo->SetReferrer(internalReferrer);
|
||||
}
|
||||
}
|
||||
else
|
||||
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
|
||||
/*
|
||||
* LoadURI(...) will cancel all refresh timers... This causes the
|
||||
* Timer and its refreshData instance to be released...
|
||||
/* for redirects we mimic HTTP, which passes the
|
||||
* original referrer
|
||||
*/
|
||||
LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
|
||||
return NS_OK;
|
||||
nsCOMPtr<nsIURI> internalReferrer;
|
||||
GetReferringURI(getter_AddRefs(internalReferrer));
|
||||
if (internalReferrer) {
|
||||
loadInfo->SetReferrer(internalReferrer);
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
|
||||
}
|
||||
|
||||
/*
|
||||
* LoadURI(...) will cancel all refresh timers... This causes the
|
||||
* Timer and its refreshData instance to be released...
|
||||
*/
|
||||
LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -4826,6 +4844,18 @@ nsDocShell::SetupRefreshURIFromHeader(nsIURI * aBaseURI,
|
|||
CheckLoadURI(aBaseURI, uri,
|
||||
nsIScriptSecurityManager::
|
||||
LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRBool isjs = PR_TRUE;
|
||||
rv = NS_URIChainHasFlags(uri,
|
||||
nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (isjs) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Since we can't travel back in time yet, just pretend
|
||||
// negative numbers do nothing at all.
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
nsDocShellLoadInfo::nsDocShellLoadInfo()
|
||||
: mInheritOwner(PR_FALSE),
|
||||
mOwnerIsExplicit(PR_FALSE),
|
||||
mSendReferrer(PR_TRUE),
|
||||
mLoadType(nsIDocShellLoadInfo::loadNormal)
|
||||
{
|
||||
|
@ -118,6 +119,18 @@ NS_IMETHODIMP nsDocShellLoadInfo::SetInheritOwner(PRBool aInheritOwner)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocShellLoadInfo::GetOwnerIsExplicit(PRBool* aOwnerIsExplicit)
|
||||
{
|
||||
*aOwnerIsExplicit = mOwnerIsExplicit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocShellLoadInfo::SetOwnerIsExplicit(PRBool aOwnerIsExplicit)
|
||||
{
|
||||
mOwnerIsExplicit = aOwnerIsExplicit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsDocShellLoadInfo::GetLoadType(nsDocShellInfoLoadType * aLoadType)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aLoadType);
|
||||
|
|
|
@ -66,6 +66,7 @@ protected:
|
|||
nsCOMPtr<nsIURI> mReferrer;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
PRPackedBool mInheritOwner;
|
||||
PRPackedBool mOwnerIsExplicit;
|
||||
PRPackedBool mSendReferrer;
|
||||
nsDocShellInfoLoadType mLoadType;
|
||||
nsCOMPtr<nsISHEntry> mSHEntry;
|
||||
|
|
|
@ -51,7 +51,7 @@ interface nsISHEntry;
|
|||
|
||||
typedef long nsDocShellInfoLoadType;
|
||||
|
||||
[scriptable, uuid(4f813a88-7aca-4607-9896-d97270cdf15e)]
|
||||
[scriptable, uuid(92a0a637-373e-4647-9476-ead11e005c75)]
|
||||
interface nsIDocShellLoadInfo : nsISupports
|
||||
{
|
||||
/** This is the referrer for the load. */
|
||||
|
@ -67,6 +67,14 @@ interface nsIDocShellLoadInfo : nsISupports
|
|||
*/
|
||||
attribute boolean inheritOwner;
|
||||
|
||||
/** If this attribute is true only ever use the owner specify by
|
||||
* the owner and inheritOwner attributes.
|
||||
* If there are security reasons for why this is unsafe, such
|
||||
* as trying to use a systemprincipal owner for a content docshell
|
||||
* the load fails.
|
||||
*/
|
||||
attribute boolean ownerIsExplicit;
|
||||
|
||||
/* these are load type enums... */
|
||||
const long loadNormal = 0; // Normal Load
|
||||
const long loadNormalReplace = 1; // Normal Load but replaces current history slot
|
||||
|
|
|
@ -69,6 +69,8 @@ _TEST_FILES = \
|
|||
bug413310-subframe.html \
|
||||
bug413310-post.sjs \
|
||||
test_bug402210.html \
|
||||
test_bug475636.html \
|
||||
file_bug475636.sjs \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
jsURL = "javascript:" + escape('window.parent.postMessage("JS uri ran", "*");\
|
||||
return \'\
|
||||
<script>\
|
||||
window.parent.postMessage("Able to access private: " +\
|
||||
window.parent.private, "*");\
|
||||
</script>\'');
|
||||
dataURL = "data:text/html," + escape('<!DOCTYPE HTML>\
|
||||
<script>\
|
||||
try {\
|
||||
window.parent.postMessage("Able to access private: " +\
|
||||
window.parent.private, "*");\
|
||||
}\
|
||||
catch (e) {\
|
||||
window.parent.postMessage("pass", "*");\
|
||||
}\
|
||||
</script>');
|
||||
|
||||
tests = [
|
||||
// Plain document should work as normal
|
||||
'<!DOCTYPE HTML>\
|
||||
<script>\
|
||||
try {\
|
||||
window.parent.private;\
|
||||
window.parent.postMessage("pass", "*");\
|
||||
}\
|
||||
catch (e) {\
|
||||
window.parent.postMessage("Unble to access private", "*");\
|
||||
}\
|
||||
</script>',
|
||||
|
||||
// refresh to plain doc
|
||||
{ refresh: "file_bug475636.sjs?1",
|
||||
doc: '<!DOCTYPE HTML>' },
|
||||
|
||||
// meta-refresh to plain doc
|
||||
'<!DOCTYPE HTML>\
|
||||
<head>\
|
||||
<meta http-equiv="refresh" content="0; url=file_bug475636.sjs?1">\
|
||||
</head>',
|
||||
|
||||
// refresh to data url
|
||||
{ refresh: dataURL,
|
||||
doc: '<!DOCTYPE HTML>' },
|
||||
|
||||
// meta-refresh to data url
|
||||
'<!DOCTYPE HTML>\
|
||||
<head>\
|
||||
<meta http-equiv="refresh" content="0; url=' + dataURL + '">\
|
||||
</head>',
|
||||
|
||||
// refresh to js url should not be followed
|
||||
{ refresh: jsURL,
|
||||
doc:
|
||||
'<!DOCTYPE HTML>\
|
||||
<script>\
|
||||
setTimeout(function() {\
|
||||
window.parent.postMessage("pass", "*");\
|
||||
}, 2000);\
|
||||
</script>' },
|
||||
|
||||
// meta refresh to js url should not be followed
|
||||
'<!DOCTYPE HTML>\
|
||||
<head>\
|
||||
<meta http-equiv="refresh" content="0; url=' + jsURL + '">\
|
||||
</head>\
|
||||
<script>\
|
||||
setTimeout(function() {\
|
||||
window.parent.postMessage("pass", "*");\
|
||||
}, 2000);\
|
||||
</script>'
|
||||
];
|
||||
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
dump("@@@@@@@@@hi there: " + request.queryString + "\n");
|
||||
test = tests[parseInt(request.queryString, 10) - 1];
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
|
||||
if (!test) {
|
||||
response.write('<script>parent.postMessage("done", "*");</script>');
|
||||
}
|
||||
else if (typeof test == "string") {
|
||||
response.write(test);
|
||||
}
|
||||
else if (test.refresh) {
|
||||
response.setHeader("Refresh", "0; url=" + test.refresh);
|
||||
response.write(test.doc);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=475636
|
||||
Test that refresh to data: URIs don't inherit the principal
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 475636</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.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 onload="gen.next()">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=475636">Mozilla Bug 475636</a>
|
||||
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<iframe id=loader></iframe>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript;version=1.8">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
gen = runTests();
|
||||
|
||||
window.private = 42;
|
||||
|
||||
window.addEventListener("message", function(e) {
|
||||
gen.send(e.data);
|
||||
}, false);
|
||||
|
||||
var url = "file_bug475636.sjs?";
|
||||
|
||||
function runTests() {
|
||||
var loader = document.getElementById('loader');
|
||||
for (var testNum = 1; ; ++testNum) {
|
||||
loader.src = url + testNum;
|
||||
let res = (yield);
|
||||
if (res == "done") {
|
||||
SimpleTest.finish();
|
||||
yield;
|
||||
}
|
||||
is(res, "pass");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1209,6 +1209,10 @@ nsExpatDriver::ConsumeToken(nsScanner& aScanner, PRBool& aFlushTokens)
|
|||
aScanner.EndReading(end);
|
||||
}
|
||||
|
||||
if (start == end && !aScanner->IsIncremental()) {
|
||||
mInternalState = kEOF;
|
||||
}
|
||||
|
||||
aScanner.SetPosition(currentExpatPosition, PR_TRUE);
|
||||
aScanner.Mark();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче