From 2815cc73cfd9d8ced889e00e72899708220d184f Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Sun, 10 Dec 2023 20:39:43 +0800 Subject: [PATCH] Merge pull request from GHSA-mj22-23ff-2hrr * WIP * WIP * Handle parsing error * Fix matching origin issue --- server/server.js | 5 +++++ server/uptime-kuma-server.js | 38 ++++++++++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/server/server.js b/server/server.js index 13dd1601..11174f76 100644 --- a/server/server.js +++ b/server/server.js @@ -48,8 +48,13 @@ if (! process.env.NODE_ENV) { process.env.NODE_ENV = "production"; } +if (!process.env.UPTIME_KUMA_WS_ORIGIN_CHECK) { + process.env.UPTIME_KUMA_WS_ORIGIN_CHECK = "cors-like"; +} + log.info("server", "Node Env: " + process.env.NODE_ENV); log.info("server", "Inside Container: " + (process.env.UPTIME_KUMA_IS_CONTAINER === "1")); +log.info("server", "WebSocket Origin Check: " + process.env.UPTIME_KUMA_WS_ORIGIN_CHECK); log.info("server", "Importing Node libraries"); const fs = require("fs"); diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 28df6461..07dfc30f 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -4,7 +4,7 @@ const fs = require("fs"); const http = require("http"); const { Server } = require("socket.io"); const { R } = require("redbean-node"); -const { log } = require("../src/util"); +const { log, isDev } = require("../src/util"); const Database = require("./database"); const util = require("util"); const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent"); @@ -103,7 +103,41 @@ class UptimeKumaServer { UptimeKumaServer.monitorTypeList["real-browser"] = new RealBrowserMonitorType(); UptimeKumaServer.monitorTypeList["tailscale-ping"] = new TailscalePing(); - this.io = new Server(this.httpServer); + this.io = new Server(this.httpServer, { + allowRequest: (req, callback) => { + let isOriginValid = true; + const bypass = isDev || process.env.UPTIME_KUMA_WS_ORIGIN_CHECK === "bypass"; + + if (!bypass) { + let host = req.headers.host; + + // If this is set, it means the request is from the browser + let origin = req.headers.origin; + + // If this is from the browser, check if the origin is allowed + if (origin) { + try { + let originURL = new URL(origin); + + if (host !== originURL.host) { + isOriginValid = false; + log.error("auth", `Origin (${origin}) does not match host (${host}), IP: ${req.socket.remoteAddress}`); + } + } catch (e) { + // Invalid origin url, probably not from browser + isOriginValid = false; + log.error("auth", `Invalid origin url (${origin}), IP: ${req.socket.remoteAddress}`); + } + } else { + log.info("auth", `Origin is not set, IP: ${req.socket.remoteAddress}`); + } + } else { + log.debug("auth", "Origin check is bypassed"); + } + + callback(null, isOriginValid); + } + }); } /** Initialise app after the database has been set up */