Bug 1714299 - Correct the opaque response judgment for opaque response blocking. r=necko-reviewers,annevk,dragana

An opaque response should be not only cross-origin but also be request with no_cors request mode.

To filter out the request with mode Same_origin, navigate, and cors. This patch reuses the algorithm in InternalRequest/FetchDriver to decide whether a response is an opaque response.

https://searchfox.org/mozilla-central/rev/da5d08750e504f3710f7ea051327d9c311c39902/dom/fetch/InternalRequest.cpp#331
https://searchfox.org/mozilla-central/rev/da5d08750e504f3710f7ea051327d9c311c39902/dom/fetch/FetchDriver.cpp#1153,1157

Differential Revision: https://phabricator.services.mozilla.com/D117086
This commit is contained in:
Eden Chuang 2021-06-22 13:11:08 +00:00
Родитель d7c2b12fbe
Коммит ef08c8d49b
5 изменённых файлов: 150 добавлений и 32 удалений

Просмотреть файл

@ -2800,32 +2800,38 @@ bool HttpBaseChannel::EnsureOpaqueResponseIsAllowed() {
return true;
}
// Check if it's cross-origin without CORS.
const bool isPrivateWin =
mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
bool isSameOrigin = false;
principal->IsSameOrigin(mURI, isPrivateWin, &isSameOrigin);
if (isSameOrigin) {
// Check if the response is a opaque response, which means requestMode should
// be RequestMode::No_cors and responseType should be ResponseType::Opaque.
nsContentPolicyType contentPolicy = mLoadInfo->InternalContentPolicyType();
// Skip the RequestMode would be RequestMode::Navigate
if (contentPolicy == nsIContentPolicy::TYPE_DOCUMENT ||
contentPolicy == nsIContentPolicy::TYPE_SUBDOCUMENT ||
contentPolicy == nsIContentPolicy::TYPE_INTERNAL_FRAME ||
contentPolicy == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
// Skip the RequestMode would be RequestMode::Same_origin
contentPolicy == nsIContentPolicy::TYPE_INTERNAL_WORKER ||
contentPolicy == nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER) {
return true;
}
nsAutoCString corsOrigin;
nsresult rv = mResponseHead->GetHeader(
nsHttp::ResolveAtom("Access-Control-Allow-Origin"_ns), corsOrigin);
if (NS_SUCCEEDED(rv)) {
if (corsOrigin.Equals("*")) {
return true;
}
uint32_t securityMode = mLoadInfo->GetSecurityMode();
// Skip when RequestMode would not be RequestMode::no_cors
if (securityMode !=
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT &&
securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL) {
return true;
}
nsCOMPtr<nsIURI> corsOriginURI;
rv = NS_NewURI(getter_AddRefs(corsOriginURI), corsOrigin);
if (NS_SUCCEEDED(rv)) {
bool isSameOrigin = false;
principal->IsSameOrigin(corsOriginURI, isPrivateWin, &isSameOrigin);
if (isSameOrigin) {
return true;
}
}
// Only continue when ResponseType would be ResponseType::Opaque
if (mLoadInfo->GetTainting() != mozilla::LoadTainting::Opaque) {
return true;
}
// Exclude object/embed element
auto extContentPolicyType = mLoadInfo->GetExternalContentPolicyType();
if (extContentPolicyType == ExtContentPolicy::TYPE_OBJECT ||
extContentPolicyType == ExtContentPolicy::TYPE_OBJECT_SUBREQUEST) {
return true;
}
InitiateORBTelemetry();

Просмотреть файл

@ -29,6 +29,8 @@ support-files =
res_not_200or206.mp3^headers^
res_img_for_unknown_decoder
res_img_for_unknown_decoder^headers^
res_object.html
res_sub_document.html
[browser_about_cache.js]
[browser_bug1535877.js]

Просмотреть файл

@ -29,6 +29,8 @@ const MEDIA_206_URL = `${ORIGIN2}/${DIRPATH}res_206.mp3`;
const MEDIA_INVALID_PARTIAL_URL = `${ORIGIN2}/${DIRPATH}res_invalid_partial.mp3`;
const MEDIA_NOT_200OR206_URL = `${ORIGIN2}/${DIRPATH}res_not_200or206.mp3`;
const IMAGE_UNKNOWN_DECOEDER_URL = `${ORIGIN2}/${DIRPATH}res_img_for_unknown_decoder`;
const SUBDOCUMENT_URL = `${ORIGIN2}/${DIRPATH}/res_sub_document.html`;
const SAME_ORIGIN_OBJECT_URL = `${ORIGIN1}/${DIRPATH}/res_object.html`;
add_task(async function() {
await SpecialPowers.pushPrefEnv({
@ -41,62 +43,100 @@ add_task(async function() {
{
url: SAFE_LISTED_URL,
key: "Allowed_SafeListed",
shouldRecorded: true,
},
{
url: BLOCKED_LISTED_NEVER_SNIFFED_URL,
key: "Blocked_BlockListedNeverSniffed",
shouldRecorded: true,
},
{
url: BLOCKED_LISTED_206_URL,
key: "Blocked_206AndBlockListed",
shouldRecorded: true,
},
{
url: BLOCKED_LISTED_NOSNIFF_URL,
key: "Blocked_NosniffAndEitherBlockListedOrTextPlain",
shouldRecorded: true,
},
{
url: IMAGE_URL,
key: "Allowed_SniffAsImageOrAudioOrVideo",
shouldRecorded: true,
},
{
url: NOSNIFF_URL,
key: "Blocked_NoSniffHeaderAfterSniff",
shouldRecorded: true,
},
{
url: NOT_OK_URL,
key: "Blocked_ResponseNotOk",
shouldRecorded: true,
},
{
url: UNKNOWN_URL,
key: "Allowed_FailtoGetMIMEType",
shouldRecorded: true,
},
{
url: IMAGE_UNKNOWN_URL,
key: "Blocked_ContentTypeBeginsWithImageOrVideoOrAudio",
shouldRecorded: true,
},
{
url: MEDIA_URL,
key: "Allowed_SniffAsImageOrAudioOrVideo",
media: true,
shouldRecorded: true,
loadType: "media",
},
{
url: MEDIA_206_URL,
key: "Allowed_SniffAsImageOrAudioOrVideo",
media: true,
shouldRecorded: true,
loadType: "media",
},
{
url: MEDIA_INVALID_PARTIAL_URL,
key: "Blocked_InvaliidPartialResponse",
media: true,
shouldRecorded: true,
loadType: "media",
},
{
url: MEDIA_NOT_200OR206_URL,
key: "Blocked_Not200Or206",
media: true,
shouldRecorded: true,
loadType: "media",
},
{
url: IMAGE_UNKNOWN_DECOEDER_URL,
key: "Allowed_SniffAsImageOrAudioOrVideo",
shouldRecorded: true,
},
{
url: SUBDOCUMENT_URL,
key: "Allowed_NotImplementOrPass",
shouldRecorded: false,
loadType: "iframe",
},
{
url: IMAGE_URL,
key: "Allowed_SniffAsImageOrAudioOrVideo",
shouldRecorded: false,
loadType: "object",
},
{
url: SAME_ORIGIN_OBJECT_URL,
key: "Allowed_SniffAsImageOrAudioOrVideo",
shouldRecorded: false,
loadType: "object",
},
{
url: IMAGE_URL,
key: "Allowed_SniffAsImageOrAudioOrVideo",
shouldRecorded: false,
loadType: "embed",
},
];
@ -111,10 +151,10 @@ add_task(async function() {
await SpecialPowers.spawn(
browser,
[testcase.url, testcase.media],
async (url, media) => {
[testcase.url, testcase.loadType, testcase.iframe],
async (url, loadType, iframe) => {
try {
if (media) {
if (loadType == "media") {
const audio = content.document.createElement("audio");
audio.src = url;
content.document.body.appendChild(audio);
@ -127,9 +167,43 @@ add_task(async function() {
res();
};
});
} else {
await content.window.fetch(url);
return;
}
if (loadType == "iframe") {
const subframe = content.document.createElement("iframe");
subframe.src = url;
const onloadPromise = new Promise(res => {
subframe.onload = res;
});
content.document.body.appendChild(subframe);
await onloadPromise;
content.document.body.removeChild(subframe);
return;
}
if (loadType == "object") {
const object = content.document.createElement("object");
object.data = url;
const onloadPromise = new Promise(res => {
object.onload = res;
});
content.document.body.appendChild(object);
await onloadPromise;
content.document.body.removeChild(object);
return;
}
if (loadType == "embed") {
const embed = content.document.createElement("embed");
embed.src = url;
const onloadPromise = new Promise(res => {
embed.onload = res;
});
content.document.body.appendChild(embed);
await onloadPromise;
content.document.body.removeChild(embed);
return;
}
await content.window.fetch(url, { mode: "no-cors" });
} catch (e) {
/* Ignore result */
}
@ -145,7 +219,14 @@ add_task(async function() {
keys = [testcase.key];
}
for (let key of keys) {
ok(snapshot.hasOwnProperty(key), `Should have recorded key ${key}`);
if (testcase.shouldRecorded) {
ok(snapshot.hasOwnProperty(key), `Should have recorded key ${key}`);
} else {
ok(
!snapshot.hasOwnProperty(key),
`Should not have recorded key ${key}`
);
}
}
}
});

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<html>
<body>
<p>Dummy Page</p>
<script>
let foo = async () => {
let url = "https://example.org/browser/netwerk/test/browser/res_img.png";
await fetch(url, { mode: "no-cors" });
}
foo();
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,11 @@
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<html>
<body>
<p>Dummy Page</p>
</body>
</html>