mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-22 16:29:09 +01:00
[PM-4830] Fix unsafe origin source (#6884)
* feat: add inscure types and remove the insecure fields from the page-script * feat: securely set variables in content-script * chore: clean up comments
This commit is contained in:
parent
4c8193060d
commit
61ca0e893e
@ -1,3 +1,8 @@
|
||||
import {
|
||||
AssertCredentialParams,
|
||||
CreateCredentialParams,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
|
||||
import { Message, MessageType } from "./messaging/message";
|
||||
import { Messenger } from "./messaging/messenger";
|
||||
|
||||
@ -40,6 +45,14 @@ async function hasActiveUser() {
|
||||
return activeUserStorageValue[activeUserIdKey] !== undefined;
|
||||
}
|
||||
|
||||
function isSameOriginWithAncestors() {
|
||||
try {
|
||||
return window.self === window.top;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function initializeFido2ContentScript() {
|
||||
const s = document.createElement("script");
|
||||
s.src = chrome.runtime.getURL("content/fido2/page-script.js");
|
||||
@ -58,10 +71,16 @@ function initializeFido2ContentScript() {
|
||||
|
||||
if (message.type === MessageType.CredentialCreationRequest) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const data: CreateCredentialParams = {
|
||||
...message.data,
|
||||
origin: window.location.origin,
|
||||
sameOriginWithAncestors: isSameOriginWithAncestors(),
|
||||
};
|
||||
|
||||
chrome.runtime.sendMessage(
|
||||
{
|
||||
command: "fido2RegisterCredentialRequest",
|
||||
data: message.data,
|
||||
data,
|
||||
requestId: requestId,
|
||||
},
|
||||
(response) => {
|
||||
@ -80,10 +99,16 @@ function initializeFido2ContentScript() {
|
||||
|
||||
if (message.type === MessageType.CredentialGetRequest) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const data: AssertCredentialParams = {
|
||||
...message.data,
|
||||
origin: window.location.origin,
|
||||
sameOriginWithAncestors: isSameOriginWithAncestors(),
|
||||
};
|
||||
|
||||
chrome.runtime.sendMessage(
|
||||
{
|
||||
command: "fido2GetCredentialRequest",
|
||||
data: message.data,
|
||||
data,
|
||||
requestId: requestId,
|
||||
},
|
||||
(response) => {
|
||||
|
@ -15,9 +15,19 @@ export enum MessageType {
|
||||
ErrorResponse,
|
||||
}
|
||||
|
||||
/**
|
||||
* The params provided by the page-script are created in an insecure environemnt and
|
||||
* should not be trusted. This type is used to ensure that the content-script does not
|
||||
* trust the `origin` or `sameOriginWithAncestors` params.
|
||||
*/
|
||||
export type InsecureCreateCredentialParams = Omit<
|
||||
CreateCredentialParams,
|
||||
"origin" | "sameOriginWithAncestors"
|
||||
>;
|
||||
|
||||
export type CredentialCreationRequest = {
|
||||
type: MessageType.CredentialCreationRequest;
|
||||
data: CreateCredentialParams;
|
||||
data: InsecureCreateCredentialParams;
|
||||
};
|
||||
|
||||
export type CredentialCreationResponse = {
|
||||
@ -25,9 +35,19 @@ export type CredentialCreationResponse = {
|
||||
result?: CreateCredentialResult;
|
||||
};
|
||||
|
||||
/**
|
||||
* The params provided by the page-script are created in an insecure environemnt and
|
||||
* should not be trusted. This type is used to ensure that the content-script does not
|
||||
* trust the `origin` or `sameOriginWithAncestors` params.
|
||||
*/
|
||||
export type InsecureAssertCredentialParams = Omit<
|
||||
AssertCredentialParams,
|
||||
"origin" | "sameOriginWithAncestors"
|
||||
>;
|
||||
|
||||
export type CredentialGetRequest = {
|
||||
type: MessageType.CredentialGetRequest;
|
||||
data: AssertCredentialParams;
|
||||
data: InsecureAssertCredentialParams;
|
||||
};
|
||||
|
||||
export type CredentialGetResponse = {
|
||||
|
@ -52,16 +52,7 @@ const browserCredentials = {
|
||||
get: navigator.credentials.get.bind(navigator.credentials) as typeof navigator.credentials.get,
|
||||
};
|
||||
|
||||
const messenger = Messenger.forDOMCommunication(window);
|
||||
|
||||
function isSameOriginWithAncestors() {
|
||||
try {
|
||||
return window.self === window.top;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const messenger = ((window as any).messenger = Messenger.forDOMCommunication(window));
|
||||
navigator.credentials.create = async (
|
||||
options?: CredentialCreationOptions,
|
||||
abortController?: AbortController
|
||||
@ -76,17 +67,10 @@ navigator.credentials.create = async (
|
||||
(options?.publicKey?.authenticatorSelection.authenticatorAttachment !== "platform" &&
|
||||
browserNativeWebauthnSupport);
|
||||
try {
|
||||
const isNotIframe = isSameOriginWithAncestors();
|
||||
|
||||
const response = await messenger.request(
|
||||
{
|
||||
type: MessageType.CredentialCreationRequest,
|
||||
data: WebauthnUtils.mapCredentialCreationOptions(
|
||||
options,
|
||||
window.location.origin,
|
||||
isNotIframe,
|
||||
fallbackSupported
|
||||
),
|
||||
data: WebauthnUtils.mapCredentialCreationOptions(options, fallbackSupported),
|
||||
},
|
||||
abortController
|
||||
);
|
||||
@ -124,12 +108,7 @@ navigator.credentials.get = async (
|
||||
const response = await messenger.request(
|
||||
{
|
||||
type: MessageType.CredentialGetRequest,
|
||||
data: WebauthnUtils.mapCredentialRequestOptions(
|
||||
options,
|
||||
window.location.origin,
|
||||
true,
|
||||
fallbackSupported
|
||||
),
|
||||
data: WebauthnUtils.mapCredentialRequestOptions(options, fallbackSupported),
|
||||
},
|
||||
abortController
|
||||
);
|
||||
|
@ -1,18 +1,19 @@
|
||||
import {
|
||||
CreateCredentialParams,
|
||||
CreateCredentialResult,
|
||||
AssertCredentialParams,
|
||||
AssertCredentialResult,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { Fido2Utils } from "@bitwarden/common/vault/services/fido2/fido2-utils";
|
||||
|
||||
import {
|
||||
InsecureAssertCredentialParams,
|
||||
InsecureCreateCredentialParams,
|
||||
} from "./content/messaging/message";
|
||||
|
||||
export class WebauthnUtils {
|
||||
static mapCredentialCreationOptions(
|
||||
options: CredentialCreationOptions,
|
||||
origin: string,
|
||||
sameOriginWithAncestors: boolean,
|
||||
fallbackSupported: boolean
|
||||
): CreateCredentialParams {
|
||||
): InsecureCreateCredentialParams {
|
||||
const keyOptions = options.publicKey;
|
||||
|
||||
if (keyOptions == undefined) {
|
||||
@ -20,7 +21,6 @@ export class WebauthnUtils {
|
||||
}
|
||||
|
||||
return {
|
||||
origin,
|
||||
attestation: keyOptions.attestation,
|
||||
authenticatorSelection: {
|
||||
requireResidentKey: keyOptions.authenticatorSelection?.requireResidentKey,
|
||||
@ -48,7 +48,6 @@ export class WebauthnUtils {
|
||||
name: keyOptions.user.name,
|
||||
},
|
||||
timeout: keyOptions.timeout,
|
||||
sameOriginWithAncestors,
|
||||
fallbackSupported,
|
||||
};
|
||||
}
|
||||
@ -93,10 +92,8 @@ export class WebauthnUtils {
|
||||
|
||||
static mapCredentialRequestOptions(
|
||||
options: CredentialRequestOptions,
|
||||
origin: string,
|
||||
sameOriginWithAncestors: boolean,
|
||||
fallbackSupported: boolean
|
||||
): AssertCredentialParams {
|
||||
): InsecureAssertCredentialParams {
|
||||
const keyOptions = options.publicKey;
|
||||
|
||||
if (keyOptions == undefined) {
|
||||
@ -104,14 +101,12 @@ export class WebauthnUtils {
|
||||
}
|
||||
|
||||
return {
|
||||
origin,
|
||||
allowedCredentialIds:
|
||||
keyOptions.allowCredentials?.map((c) => Fido2Utils.bufferToString(c.id)) ?? [],
|
||||
challenge: Fido2Utils.bufferToString(keyOptions.challenge),
|
||||
rpId: keyOptions.rpId,
|
||||
userVerification: keyOptions.userVerification,
|
||||
timeout: keyOptions.timeout,
|
||||
sameOriginWithAncestors,
|
||||
fallbackSupported,
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user