mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 761655 - Support for multiple X-Frame-Options policies (multiple headers or comma in header value). r=jst
This commit is contained in:
parent
ecc29d4288
commit
7ae666a35f
@ -14,6 +14,11 @@ window.addEventListener('load', parent.testFramesLoaded, false);
|
||||
<iframe id="deny" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=deny&xfo=deny"></iframe><br>
|
||||
<iframe id="sameorigin1" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin1&xfo=sameorigin"></iframe><br>
|
||||
<iframe id="sameorigin2" src="http://example.com/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin2&xfo=sameorigin"></iframe><br>
|
||||
<iframe id="sameorigin5" src="http://example.com/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin5&xfo=sameorigin2"></iframe><br>
|
||||
<iframe id="sameorigin6" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin6&xfo=sameorigin2"></iframe><br>
|
||||
<iframe id="sameorigin7" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin7&xfo=sameorigin3"></iframe><br>
|
||||
<iframe id="sameorigin8" src="http://example.com/tests/content/base/test/file_x-frame-options_page.sjs?testid=sameorigin8&xfo=sameorigin3"></iframe><br>
|
||||
<iframe id="mixedpolicy" src="http://mochi.test:8888/tests/content/base/test/file_x-frame-options_page.sjs?testid=mixedpolicy&xfo=mixedpolicy"></iframe><br>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -17,6 +17,15 @@ function handleRequest(request, response)
|
||||
else if (query['xfo'] == "sameorigin") {
|
||||
response.setHeader("X-Frame-Options", "SAMEORIGIN", false);
|
||||
}
|
||||
else if (query['xfo'] == "sameorigin2") {
|
||||
response.setHeader("X-Frame-Options", "SAMEORIGIN, SAMEORIGIN", false);
|
||||
}
|
||||
else if (query['xfo'] == "sameorigin3") {
|
||||
response.setHeader("X-Frame-Options", "SAMEORIGIN,SAMEORIGIN , SAMEORIGIN", false);
|
||||
}
|
||||
else if (query['xfo'] == "mixedpolicy") {
|
||||
response.setHeader("X-Frame-Options", "DENY,SAMEORIGIN", false);
|
||||
}
|
||||
|
||||
// from the test harness we'll be checking for the presence of this element
|
||||
// to test if the page loaded
|
||||
|
@ -83,6 +83,31 @@ var testFramesLoaded = function() {
|
||||
var test5 = frame.contentDocument.getElementById("test");
|
||||
is(test5, null, "test sameorigin2");
|
||||
|
||||
// iframe from different origin, X-F-O: SAMEORIGIN, SAMEORIGIN - should not load
|
||||
frame = harness.contentDocument.getElementById("sameorigin5");
|
||||
var test6 = frame.contentDocument.getElementById("test");
|
||||
is(test6, null, "test sameorigin5");
|
||||
|
||||
// iframe from same origin, X-F-O: SAMEORIGIN, SAMEORIGIN - should load
|
||||
frame = harness.contentDocument.getElementById("sameorigin6");
|
||||
var test7 = frame.contentDocument.getElementById("test").textContent;
|
||||
is(test7, "sameorigin6", "test sameorigin6");
|
||||
|
||||
// iframe from same origin, X-F-O: SAMEORIGIN,SAMEORIGIN, SAMEORIGIN - should load
|
||||
frame = harness.contentDocument.getElementById("sameorigin7");
|
||||
var test8 = frame.contentDocument.getElementById("test").textContent;
|
||||
is(test8, "sameorigin7", "test sameorigin7");
|
||||
|
||||
// iframe from same origin, X-F-O: SAMEORIGIN,SAMEORIGIN, SAMEORIGIN - should not load
|
||||
frame = harness.contentDocument.getElementById("sameorigin8");
|
||||
var test9 = frame.contentDocument.getElementById("test");
|
||||
is(test9, null, "test sameorigin8");
|
||||
|
||||
// iframe from same origin, X-F-O: DENY,SAMEORIGIN - should not load
|
||||
frame = harness.contentDocument.getElementById("mixedpolicy");
|
||||
var test10 = frame.contentDocument.getElementById("test");
|
||||
is(test10, null, "test mixedpolicy");
|
||||
|
||||
// call tests to check principal comparison, e.g. a document can open a window
|
||||
// to a data: or javascript: document which frames an
|
||||
// X-Frame-Options: SAMEORIGIN document and the frame should load
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsNetError.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -269,29 +270,18 @@ nsDSURIContentListener::SetParentContentListener(nsIURIContentListener*
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check if X-Frame-Options permits this document to be loaded as a subdocument.
|
||||
bool nsDSURIContentListener::CheckFrameOptions(nsIRequest* request)
|
||||
{
|
||||
// If X-Frame-Options checking is disabled, return true unconditionally.
|
||||
if (sIgnoreXFrameOptions) {
|
||||
bool nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIRequest *request,
|
||||
const nsAString& policy) {
|
||||
// return early if header does not have one of the two values with meaning
|
||||
if (!policy.LowerCaseEqualsLiteral("deny") &&
|
||||
!policy.LowerCaseEqualsLiteral("sameorigin"))
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCAutoString xfoHeaderValue;
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
|
||||
if (!httpChannel) {
|
||||
return true;
|
||||
}
|
||||
|
||||
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-Frame-Options"),
|
||||
xfoHeaderValue);
|
||||
|
||||
// return early if header does not have one of the two values with meaning
|
||||
if (!xfoHeaderValue.LowerCaseEqualsLiteral("deny") &&
|
||||
!xfoHeaderValue.LowerCaseEqualsLiteral("sameorigin"))
|
||||
return true;
|
||||
|
||||
if (mDocShell) {
|
||||
// We need to check the location of this window and the location of the top
|
||||
// window, if we're not the top. X-F-O: SAMEORIGIN requires that the
|
||||
@ -321,8 +311,10 @@ bool nsDSURIContentListener::CheckFrameOptions(nsIRequest* request)
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIScriptSecurityManager> ssm =
|
||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
|
||||
if (!ssm)
|
||||
if (!ssm) {
|
||||
NS_ASSERTION(ssm, "Failed to get the ScriptSecurityManager.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Traverse up the parent chain to the top docshell that doesn't have
|
||||
// a system principal
|
||||
@ -333,6 +325,7 @@ bool nsDSURIContentListener::CheckFrameOptions(nsIRequest* request)
|
||||
if (topDoc) {
|
||||
if (NS_SUCCEEDED(ssm->IsSystemPrincipal(topDoc->NodePrincipal(),
|
||||
&system)) && system) {
|
||||
// Found a system-principled doc: last docshell was top.
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -347,34 +340,71 @@ bool nsDSURIContentListener::CheckFrameOptions(nsIRequest* request)
|
||||
if (curDocShellItem == thisDocShellItem)
|
||||
return true;
|
||||
|
||||
// If the value of the header is DENY, and the previous condition is
|
||||
// not met (current docshell is not the top docshell), prohibit the
|
||||
// load.
|
||||
if (policy.LowerCaseEqualsLiteral("deny")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the X-Frame-Options value is SAMEORIGIN, then the top frame in the
|
||||
// parent chain must be from the same origin as this document.
|
||||
if (xfoHeaderValue.LowerCaseEqualsLiteral("sameorigin")) {
|
||||
if (policy.LowerCaseEqualsLiteral("sameorigin")) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
httpChannel->GetURI(getter_AddRefs(uri));
|
||||
topDoc = do_GetInterface(curDocShellItem);
|
||||
nsCOMPtr<nsIURI> topUri;
|
||||
topDoc->NodePrincipal()->GetURI(getter_AddRefs(topUri));
|
||||
rv = ssm->CheckSameOriginURI(uri, topUri, true);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
return true;
|
||||
if (NS_FAILED(rv))
|
||||
return false; /* wasn't same-origin */
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if X-Frame-Options permits this document to be loaded as a subdocument.
|
||||
// This will iterate through and check any number of X-Frame-Options policies
|
||||
// in the request (comma-separated in a header, multiple headers, etc).
|
||||
bool nsDSURIContentListener::CheckFrameOptions(nsIRequest *request)
|
||||
{
|
||||
// If X-Frame-Options checking is disabled, return true unconditionally.
|
||||
if (sIgnoreXFrameOptions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
|
||||
if (!httpChannel) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCAutoString xfoHeaderCValue;
|
||||
httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-Frame-Options"),
|
||||
xfoHeaderCValue);
|
||||
NS_ConvertUTF8toUTF16 xfoHeaderValue(xfoHeaderCValue);
|
||||
|
||||
// if no header value, there's nothing to do.
|
||||
if (xfoHeaderValue.IsEmpty())
|
||||
return true;
|
||||
|
||||
// iterate through all the header values (usually there's only one, but can
|
||||
// be many. If any want to deny the load, deny the load.
|
||||
nsCharSeparatedTokenizer tokenizer(xfoHeaderValue, ',');
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsSubstring& tok = tokenizer.nextToken();
|
||||
if (!CheckOneFrameOptionsPolicy(request, tok)) {
|
||||
// cancel the load and display about:blank
|
||||
httpChannel->Cancel(NS_BINDING_ABORTED);
|
||||
if (mDocShell) {
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryObject(mDocShell));
|
||||
if (webNav) {
|
||||
webNav->LoadURI(NS_LITERAL_STRING("about:blank").get(),
|
||||
0, nsnull, nsnull, nsnull);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
else {
|
||||
// If the value of the header is DENY, then the document
|
||||
// should never be permitted to load as a subdocument.
|
||||
NS_ASSERTION(xfoHeaderValue.LowerCaseEqualsLiteral("deny"),
|
||||
"How did we get here with some random header value?");
|
||||
}
|
||||
|
||||
// cancel the load and display about:blank
|
||||
httpChannel->Cancel(NS_BINDING_ABORTED);
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryObject(mDocShell));
|
||||
if (webNav) {
|
||||
webNav->LoadURI(NS_LITERAL_STRING("about:blank").get(),
|
||||
0, nsnull, nsnull, nsnull);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -38,6 +38,8 @@ protected:
|
||||
// Determine if X-Frame-Options allows content to be framed
|
||||
// as a subdocument
|
||||
bool CheckFrameOptions(nsIRequest* request);
|
||||
bool CheckOneFrameOptionsPolicy(nsIRequest* request,
|
||||
const nsAString& policy);
|
||||
|
||||
protected:
|
||||
nsDocShell* mDocShell;
|
||||
|
Loading…
Reference in New Issue
Block a user