Skip to content

Commit 8744ad0

Browse files
authored
[server] verifyClient: Remove dead code to parse workspace URLs (#16845)
1 parent 7ce3c55 commit 8744ad0

File tree

3 files changed

+12
-68
lines changed

3 files changed

+12
-68
lines changed

components/server/src/express-util.spec.ts

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ describe("express-util", function () {
1515
const result = isAllowedWebsocketDomain(
1616
"http://3000-moccasin-ferret-155799b3.ws-eu.gpl-2732-ws-csrf.staging.gitpod.io",
1717
HOSTURL_HOSTNAME,
18-
false,
1918
);
2019
expect(result).to.be.false;
2120
});
@@ -24,24 +23,18 @@ describe("express-util", function () {
2423
const result = isAllowedWebsocketDomain(
2524
"http://moccasin-ferret-155799b3.ws-eu.gpl-2732-ws-csrf.staging.gitpod.io",
2625
HOSTURL_HOSTNAME,
27-
false,
2826
);
2927
expect(result).to.be.true;
3028
});
3129

3230
it("should return true for dashboard", function () {
33-
const result = isAllowedWebsocketDomain(
34-
"http://gpl-2732-ws-csrf.staging.gitpod.io",
35-
HOSTURL_HOSTNAME,
36-
false,
37-
);
31+
const result = isAllowedWebsocketDomain("http://gpl-2732-ws-csrf.staging.gitpod.io", HOSTURL_HOSTNAME);
3832
expect(result).to.be.true;
3933
});
4034
it("should return false for workspace-port locations (strict)", function () {
4135
const result = isAllowedWebsocketDomain(
4236
"http://3000-moccasin-ferret-155799b3.ws-eu.gpl-2732-ws-csrf.staging.gitpod.io",
4337
HOSTURL_HOSTNAME,
44-
true,
4538
);
4639
expect(result).to.be.false;
4740
});
@@ -50,17 +43,12 @@ describe("express-util", function () {
5043
const result = isAllowedWebsocketDomain(
5144
"http://moccasin-ferret-155799b3.ws-eu.gpl-2732-ws-csrf.staging.gitpod.io",
5245
HOSTURL_HOSTNAME,
53-
true,
5446
);
5547
expect(result).to.be.false;
5648
});
5749

5850
it("should return true for dashboard (strict)", function () {
59-
const result = isAllowedWebsocketDomain(
60-
"http://gpl-2732-ws-csrf.staging.gitpod.io",
61-
HOSTURL_HOSTNAME,
62-
true,
63-
);
51+
const result = isAllowedWebsocketDomain("http://gpl-2732-ws-csrf.staging.gitpod.io", HOSTURL_HOSTNAME);
6452
expect(result).to.be.true;
6553
});
6654
});
@@ -70,34 +58,24 @@ describe("express-util", function () {
7058
const result = isAllowedWebsocketDomain(
7159
"https://8000-black-capybara-dy6e3fgz.ws-eu08.gitpod.io",
7260
HOSTURL_HOSTNAME,
73-
false,
7461
);
7562
expect(result).to.be.false;
7663
});
7764

7865
it("should return true for workspace locations", function () {
79-
const result = isAllowedWebsocketDomain(
80-
"https://bronze-bird-p2q226d8.ws-eu08.gitpod.io",
81-
HOSTURL_HOSTNAME,
82-
false,
83-
);
66+
const result = isAllowedWebsocketDomain("https://bronze-bird-p2q226d8.ws-eu08.gitpod.io", HOSTURL_HOSTNAME);
8467
expect(result).to.be.true;
8568
});
8669
it("should return false for workspace-port locations (strict)", function () {
8770
const result = isAllowedWebsocketDomain(
8871
"https://8000-black-capybara-dy6e3fgz.ws-eu08.gitpod.io",
8972
HOSTURL_HOSTNAME,
90-
true,
9173
);
9274
expect(result).to.be.false;
9375
});
9476

9577
it("should return false for workspace locations (strict)", function () {
96-
const result = isAllowedWebsocketDomain(
97-
"https://bronze-bird-p2q226d8.ws-eu08.gitpod.io",
98-
HOSTURL_HOSTNAME,
99-
true,
100-
);
78+
const result = isAllowedWebsocketDomain("https://bronze-bird-p2q226d8.ws-eu08.gitpod.io", HOSTURL_HOSTNAME);
10179
expect(result).to.be.true;
10280
});
10381
});

components/server/src/express-util.ts

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import { URL } from "url";
88
import * as express from "express";
99
import * as crypto from "crypto";
1010
import * as session from "express-session";
11-
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
12-
import { GitpodHostUrl } from "@gitpod/gitpod-protocol/lib/util/gitpod-host-url";
1311

1412
export const query = (...tuples: [string, string][]) => {
1513
if (tuples.length === 0) {
@@ -21,7 +19,7 @@ export const query = (...tuples: [string, string][]) => {
2119
// Strict: We only allow connections from the base domain, so disallow connections from all other Origins
2220
// Only (current) exception: If no Origin header is set, skip the check!
2321
// Non-Strict: "rely" on subdomain parsing (do we still need this?)
24-
export const isAllowedWebsocketDomain = (originHeader: string, gitpodHostName: string, strict: boolean): boolean => {
22+
export const isAllowedWebsocketDomain = (originHeader: string, gitpodHostName: string): boolean => {
2523
if (!originHeader) {
2624
// Origin header check not applied because of empty Origin header
2725
return true;
@@ -30,43 +28,12 @@ export const isAllowedWebsocketDomain = (originHeader: string, gitpodHostName: s
3028
try {
3129
const originUrl = new URL(originHeader);
3230
const originHostname = originUrl.hostname;
33-
if (originHostname === gitpodHostName) {
34-
return true;
35-
}
36-
37-
if (strict) {
38-
return false;
39-
}
40-
// TODO(gpl) This is only used for Bearer-Token authentication.
41-
// Does this restriction help at all, or can we remove it entirely?
42-
log.warn("Origin header check based on looksLikeWorkspaceHostname");
43-
if (looksLikeWorkspaceHostname(originUrl, gitpodHostName)) {
44-
return true;
45-
} else {
46-
return false;
47-
}
31+
return originHostname === gitpodHostName;
4832
} catch (err) {
4933
return false;
5034
}
5135
};
5236

53-
const looksLikeWorkspaceHostname = (originHostname: URL, gitpodHostName: string): boolean => {
54-
// Is prefix a valid (looking) workspace ID?
55-
const found = originHostname.toString().lastIndexOf(gitpodHostName);
56-
if (found === -1) {
57-
return false;
58-
}
59-
const url = new GitpodHostUrl(originHostname);
60-
const workspaceId = url.workspaceId;
61-
if (workspaceId) {
62-
const hostname = url.url.hostname as string;
63-
if (hostname.startsWith(workspaceId)) {
64-
return true;
65-
}
66-
}
67-
return false;
68-
};
69-
7037
export function saveSession(session: session.Session): Promise<void> {
7138
return new Promise<void>((resolve, reject) => {
7239
session.save((err: any) => {

components/server/src/server.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,12 @@ export class Server<C extends GitpodClient, S extends GitpodServer> {
153153
const websocketConnectionHandler = this.websocketConnectionHandler;
154154
this.eventEmitter.on(Server.EVENT_ON_START, (httpServer) => {
155155
// CSRF protection: check "Origin" header:
156-
// - for cookie/session auth: MUST be gitpod.io (hostUrl.hostname)
157-
// - for Bearer auth: MUST be sth with the same base domain (*.gitpod.io) (is this required?)
158-
// - edge case: empty "Origin" is always permitted (can this be removed?)
156+
// - for cookie/session AND Bearer auth: MUST be hostUrl.hostname (gitpod.io)
157+
// - edge case: empty "Origin" is always permitted
159158
// We rely on the origin header being set correctly (needed by regular clients to use Gitpod:
160159
// CORS allows subdomains to access gitpod.io)
161-
const verifyOrigin = (origin: string, strict: boolean) => {
162-
let allowedRequest = isAllowedWebsocketDomain(origin, this.config.hostUrl.url.hostname, strict);
160+
const verifyOrigin = (origin: string) => {
161+
let allowedRequest = isAllowedWebsocketDomain(origin, this.config.hostUrl.url.hostname);
163162
if (!allowedRequest && this.config.insecureNoDomain) {
164163
log.warn("Websocket connection CSRF guard disabled");
165164
allowedRequest = true;
@@ -174,7 +173,7 @@ export class Server<C extends GitpodClient, S extends GitpodServer> {
174173
let authenticatedUsingBearerToken = false;
175174
if (info.req.url === "/v1") {
176175
// Connection attempt with Bearer-Token: be less strict for now
177-
if (!verifyOrigin(info.origin, false)) {
176+
if (!verifyOrigin(info.origin)) {
178177
log.debug("Websocket connection attempt with non-matching Origin header.", {
179178
origin: info.origin,
180179
});
@@ -196,7 +195,7 @@ export class Server<C extends GitpodClient, S extends GitpodServer> {
196195

197196
if (!authenticatedUsingBearerToken) {
198197
// Connection attempt with cookie/session based authentication: be strict about where we accept connections from!
199-
if (!verifyOrigin(info.origin, true)) {
198+
if (!verifyOrigin(info.origin)) {
200199
log.debug("Websocket connection attempt with non-matching Origin header: " + info.origin);
201200
return callback(false, 403);
202201
}

0 commit comments

Comments
 (0)