1
0
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:
Andreas Coroiu 2023-11-27 13:14:33 +01:00 committed by GitHub
parent 4c8193060d
commit 61ca0e893e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 40 deletions

View File

@ -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) => {

View File

@ -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 = {

View File

@ -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
);

View File

@ -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,
};
}