Commit d8232f29 authored by Kim Paulhamus's avatar Kim Paulhamus Committed by Commit Bot

Restrict WebAuthN to "secure and same-origin with all their ancestors"

Bug: 828958
Change-Id: Ie24fb55ddf5b8180036e830cd73ae58b0fb2ccd5
Reviewed-on: https://chromium-review.googlesource.com/994177
Commit-Queue: Kim Paulhamus <kpaulhamus@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550447}
parent e273713a
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
if (document.location.host != "subdomain.example.test:8443") {
document.location = "https://subdomain.example.test:8443/credentialmanager/publickeycredential-same-origin-with-ancestors.html";
promise_test(_ => new Promise(_ => {}), "Stall tests on the wrong host.");
}
const SAME_ORIGIN = "https://subdomain.example.test:8443";
const CROSS_ORIGIN = "https://notexample.test:8443";
const VALID_IFRAME_CASES = [
{ 'outerOrigin': SAME_ORIGIN,
'innerOrigin': ''},
{ 'outerOrigin': SAME_ORIGIN,
'innerOrigin': SAME_ORIGIN}
];
const INVALID_IFRAME_CASES = [
{ 'outerOrigin': CROSS_ORIGIN,
'innerOrigin': ''},
{ 'outerOrigin': SAME_ORIGIN,
'innerOrigin': CROSS_ORIGIN},
{ 'outerOrigin': CROSS_ORIGIN,
'innerOrigin': SAME_ORIGIN},
{ 'outerOrigin': CROSS_ORIGIN,
'innerOrigin': CROSS_ORIGIN},
];
const HELPER_FILES = [
'publickey-create-helper.html', 'publickey-get-helper.html'
];
function createNestedIframeTest(outerOrigin, innerOrigin, expectation, helperfile) {
return function (t) {
window.addEventListener("load", _ => {
var iframe = document.createElement("iframe");
if (innerOrigin) {
// Nested iframe
iframe.src = outerOrigin + "/credentialmanager/resources/echoing-nester.html?origin="
+ innerOrigin + "&file=" + helperfile;
} else {
iframe.src = outerOrigin + "/credentialmanager/resources/" + helperfile;
}
window.addEventListener("message", t.step_func(e => {
if (e.source == iframe.contentWindow) {
assert_equals(e.data, expectation);
t.done();
}
}));
document.body.appendChild(iframe);
});
};
}
for (let test of VALID_IFRAME_CASES) {
for (let file of HELPER_FILES) {
async_test(createNestedIframeTest(test.outerOrigin, test.innerOrigin, "SUCCESS", file),
file + " with inner origin: " + test.innerOrigin + ", outer origin: " + test.outerOrigin + "succeeds");
}
}
for (let test of INVALID_IFRAME_CASES) {
for (let file of HELPER_FILES) {
async_test(createNestedIframeTest(test.outerOrigin, test.innerOrigin, "NotAllowedError",file),
file + " with inner origin: " + test.innerOrigin + ", outer origin: " + test.outerOrigin + "fails");
}
}
</script>
<body>
<script>
window.addEventListener('message', m => {
window.parent.postMessage(m.data, '*');
});
var u = new URL(window.location.href);
var origin = u.searchParams.has('origin') ? u.searchParams.get('origin') : window.origin;
var file = u.searchParams.has('file') ? u.searchParams.get('file') : 'passwordcredential-get.html';
var url = origin + "/credentialmanager/resources/" + file;
var i = document.createElement('iframe');
i.src = url;
document.body.appendChild(i);
</script>
</body>
...@@ -12,7 +12,7 @@ mockAuthenticator.setAttestationObject(ATTESTATION_OBJECT); ...@@ -12,7 +12,7 @@ mockAuthenticator.setAttestationObject(ATTESTATION_OBJECT);
mockAuthenticator.setAuthenticatorStatus( mockAuthenticator.setAuthenticatorStatus(
webauth.mojom.AuthenticatorStatus.SUCCESS); webauth.mojom.AuthenticatorStatus.SUCCESS);
let queryParams = new URLSearchParams(window.location.search); let queryParams = new URLSearchParams(window.location.search);
let relyingPartyId = queryParams.get('rpId'); var relyingPartyId = queryParams.has('rpId') ? queryParams.get('rpId') : document.domain;
var customPublicKey = { var customPublicKey = {
challenge: CHALLENGE, challenge: CHALLENGE,
rp: { id: relyingPartyId, name: "Acme" }, rp: { id: relyingPartyId, name: "Acme" },
...@@ -20,7 +20,9 @@ var customPublicKey = { ...@@ -20,7 +20,9 @@ var customPublicKey = {
pubKeyCredParams: PUBLIC_KEY_PARAMETERS, pubKeyCredParams: PUBLIC_KEY_PARAMETERS,
}; };
let responder = window.opener || window.parent;
navigator.credentials.create({publicKey : customPublicKey}) navigator.credentials.create({publicKey : customPublicKey})
.then(r => window.opener.postMessage("SUCCESS", "*")) .then(r => responder.postMessage("SUCCESS", "*"))
.catch(t => window.opener.postMessage(t.name, "*")); .catch(t => responder.postMessage(t.name, "*"));
</script> </script>
...@@ -13,15 +13,16 @@ mockAuthenticator.setSignature(SIGNATURE); ...@@ -13,15 +13,16 @@ mockAuthenticator.setSignature(SIGNATURE);
mockAuthenticator.setAuthenticatorStatus( mockAuthenticator.setAuthenticatorStatus(
webauth.mojom.AuthenticatorStatus.SUCCESS); webauth.mojom.AuthenticatorStatus.SUCCESS);
let queryParams = new URLSearchParams(window.location.search); let queryParams = new URLSearchParams(window.location.search);
let relyingPartyId = queryParams.get('rpId'); var relyingPartyId = queryParams.has('rpId') ? queryParams.get('rpId') : document.domain;
var customPublicKey = { var customPublicKey = {
challenge: CHALLENGE, challenge: CHALLENGE,
rpId: relyingPartyId, rpId: relyingPartyId,
allowCredentials: [ACCEPTABLE_CREDENTIAL] allowCredentials: [ACCEPTABLE_CREDENTIAL]
}; };
let responder = window.opener || window.parent;
navigator.credentials.get({publicKey : customPublicKey}) navigator.credentials.get({publicKey : customPublicKey})
.then(r => window.opener.postMessage("SUCCESS", "*")) .then(r => responder.postMessage("SUCCESS", "*"))
.catch(t => window.opener.postMessage(t.name, "*")); .catch(t => responder.postMessage(t.name, "*"));
</script> </script>
...@@ -124,9 +124,10 @@ bool CheckSecurityRequirementsBeforeRequest( ...@@ -124,9 +124,10 @@ bool CheckSecurityRequirementsBeforeRequest(
!IsSameOriginWithAncestors(resolver->GetFrame())) { !IsSameOriginWithAncestors(resolver->GetFrame())) {
resolver->Reject(DOMException::Create( resolver->Reject(DOMException::Create(
kNotAllowedError, kNotAllowedError,
"`PasswordCredential` and `FederatedCredential` objects may only be " "The following credential operations can only occur in a document which"
"stored/retrieved in a document which is same-origin with all of its " " is same-origin with all of its ancestors: "
"ancestors.")); "storage/retrieval of 'PasswordCredential' and 'FederatedCredential', "
"and creation/retrieval of 'PublicKeyCredential'"));
return false; return false;
} }
...@@ -427,10 +428,7 @@ ScriptPromise CredentialsContainer::get( ...@@ -427,10 +428,7 @@ ScriptPromise CredentialsContainer::get(
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise(); ScriptPromise promise = resolver->Promise();
auto required_origin_type = auto required_origin_type = RequiredOriginType::kSecureAndSameWithAncestors;
options.hasFederated() || options.hasPassword()
? RequiredOriginType::kSecureAndSameWithAncestors
: RequiredOriginType::kSecure;
if (!CheckSecurityRequirementsBeforeRequest(resolver, required_origin_type)) if (!CheckSecurityRequirementsBeforeRequest(resolver, required_origin_type))
return promise; return promise;
...@@ -557,7 +555,10 @@ ScriptPromise CredentialsContainer::create( ...@@ -557,7 +555,10 @@ ScriptPromise CredentialsContainer::create(
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise(); ScriptPromise promise = resolver->Promise();
const auto required_origin_type = RequiredOriginType::kSecure; auto required_origin_type =
options.hasPublicKey() ? RequiredOriginType::kSecureAndSameWithAncestors
: RequiredOriginType::kSecure;
if (!CheckSecurityRequirementsBeforeRequest(resolver, required_origin_type)) if (!CheckSecurityRequirementsBeforeRequest(resolver, required_origin_type))
return promise; return promise;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment