1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Make ws:// authentication more timing safe (#4297)

This commit is contained in:
Sebastian Malton 2021-11-09 14:24:32 -05:00 committed by GitHub
parent 18d695348b
commit 81b972a2d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 16 additions and 8 deletions

View File

@ -28,14 +28,17 @@ import URLParse from "url-parse";
import { ExtendedMap, Singleton } from "../../common/utils"; import { ExtendedMap, Singleton } from "../../common/utils";
import type { ClusterId } from "../../common/cluster-types"; import type { ClusterId } from "../../common/cluster-types";
import { ipcMainHandle } from "../../common/ipc"; import { ipcMainHandle } from "../../common/ipc";
import * as uuid from "uuid"; import crypto from "crypto";
import { promisify } from "util";
const randomBytes = promisify(crypto.randomBytes);
export class ShellRequestAuthenticator extends Singleton { export class ShellRequestAuthenticator extends Singleton {
private tokens = new ExtendedMap<ClusterId, Map<string, string>>(); private tokens = new ExtendedMap<ClusterId, Map<string, Uint8Array>>();
init() { init() {
ipcMainHandle("cluster:shell-api", (event, clusterId, tabId) => { ipcMainHandle("cluster:shell-api", async (event, clusterId, tabId) => {
const authToken = uuid.v4(); const authToken = Uint8Array.from(await randomBytes(128));
this.tokens this.tokens
.getOrInsert(clusterId, () => new Map()) .getOrInsert(clusterId, () => new Map())
@ -60,9 +63,9 @@ export class ShellRequestAuthenticator extends Singleton {
} }
const authToken = clusterTokens.get(tabId); const authToken = clusterTokens.get(tabId);
const buf = Uint8Array.from(Buffer.from(token, "base64"));
// need both conditions to prevent `undefined === undefined` being true here if (authToken instanceof Uint8Array && authToken.length === buf.length && crypto.timingSafeEqual(authToken, buf)) {
if (typeof authToken === "string" && authToken === token) {
// remove the token because it is a single use token // remove the token because it is a single use token
clusterTokens.delete(tabId); clusterTokens.delete(tabId);

View File

@ -81,7 +81,12 @@ export class TerminalApi extends WebSocketApi {
this.emitStatus("Connecting ..."); this.emitStatus("Connecting ...");
} }
const shellToken = await ipcRenderer.invoke("cluster:shell-api", getHostedClusterId(), this.query.id); const authTokenArray = await ipcRenderer.invoke("cluster:shell-api", getHostedClusterId(), this.query.id);
if (!(authTokenArray instanceof Uint8Array)) {
throw new TypeError("ShellApi token is not a Uint8Array");
}
const { hostname, protocol, port } = location; const { hostname, protocol, port } = location;
const socketUrl = url.format({ const socketUrl = url.format({
protocol: protocol.includes("https") ? "wss" : "ws", protocol: protocol.includes("https") ? "wss" : "ws",
@ -90,7 +95,7 @@ export class TerminalApi extends WebSocketApi {
pathname: "/api", pathname: "/api",
query: { query: {
...this.query, ...this.query,
shellToken, shellToken: Buffer.from(authTokenArray).toString("base64"),
}, },
slashes: true, slashes: true,
}); });